diff --git a/.php_cs b/.php_cs
index ba9d1251a..0c6b9ead7 100644
--- a/.php_cs
+++ b/.php_cs
@@ -10,9 +10,32 @@ $finder = Symfony\CS\Finder\DefaultFinder::create()
return Symfony\CS\Config\Config::create()
->setUsingCache(true)
- ->level(Symfony\CS\FixerInterface::NONE_LEVEL)
- ->fixers(array(
- 'psr0', 'encoding', 'short_tag', 'braces', 'elseif', 'eof_ending', 'function_declaration', 'indentation', 'line_after_namespace', 'linefeed', 'lowercase_constants', 'lowercase_keywords', 'multiple_use', 'php_closing_tag', 'trailing_spaces', 'visibility', 'duplicate_semicolon', 'extra_empty_lines', 'include', 'namespace_no_leading_whitespace', 'object_operator', 'operators_spaces', 'phpdoc_params', 'return', 'single_array_no_trailing_comma', 'spaces_cast', 'standardize_not_equal', 'ternary_spaces', 'unused_use', 'whitespacy_lines', 'multiline_array_tailing_comma',
+ ->setRiskyAllowed(true)
+ ->setRules(array(
+ '@PSR2' => true,
+ 'duplicate_semicolon' => true,
+ 'extra_empty_lines' => true,
+ 'include' => true,
+ 'multiline_array_trailing_comma' => true,
+ 'namespace_no_leading_whitespace' => true,
+ 'object_operator' => true,
+ 'operators_spaces' => true,
+ 'phpdoc_align' => true,
+ 'phpdoc_indent' => true,
+ 'phpdoc_no_access' => true,
+ 'phpdoc_no_package' => true,
+ 'phpdoc_order' => true,
+ 'phpdoc_scalar' => true,
+ 'phpdoc_trim' => true,
+ 'phpdoc_type_to_var' => true,
+ 'psr0' => true,
+ 'return' => true,
+ 'single_array_no_trailing_comma' => true,
+ 'spaces_cast' => true,
+ 'standardize_not_equal' => true,
+ 'ternary_spaces' => true,
+ 'unused_use' => true,
+ 'whitespacy_lines' => true,
))
->finder($finder)
;
diff --git a/.travis.yml b/.travis.yml
index b1aa4414d..383ad0334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,8 +7,9 @@ cache:
- $HOME/.composer/cache
addons:
- apt_packages:
- - parallel
+ apt:
+ packages:
+ - parallel
php:
- 5.3.3
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 786b92efd..6c3be2943 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@ Contributing to Composer
========================
Please note that this project is released with a
-[Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/).
+[Contributor Code of Conduct](http://contributor-covenant.org/version/1/2/0/).
By participating in this project you agree to abide by its terms.
Reporting Issues
@@ -42,6 +42,8 @@ Contributing policy
Fork the project, create a feature branch, and send us a pull request.
To ensure a consistent code base, you should make sure the code follows
-the [PSR-2 Coding Standards](http://www.php-fig.org/psr/psr-2/).
+the [PSR-2 Coding Standards](http://www.php-fig.org/psr/psr-2/). You can also
+run [php-cs-fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) with the
+configuration file that can be found in the project root directory.
-If you would like to help, take a look at the [list of issues](https://github.com/composer/composer/issues).
+If you would like to help, take a look at the [list of open issues](https://github.com/composer/composer/issues).
diff --git a/README.md b/README.md
index c7bcca110..ccbfdcd34 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Composer helps you declare, manage and install dependencies of PHP projects, ens
See [https://getcomposer.org/](https://getcomposer.org/) for more information and documentation.
[![Build Status](https://travis-ci.org/composer/composer.svg?branch=master)](https://travis-ci.org/composer/composer)
-[![Dependency Status](https://www.versioneye.com/php/composer:composer/dev-master/badge.svg)](https://www.versioneye.com/php/composer:composer/dev-master)
+[![Dependency Status](https://www.versioneye.com/php/composer:composer/dev-master/badge.svg)](https://www.versioneye.com/php/composer:composer/dev-master)
[![Reference Status](https://www.versioneye.com/php/composer:composer/reference_badge.svg?style=flat)](https://www.versioneye.com/php/composer:composer/references)
Installation / Usage
@@ -45,7 +45,6 @@ Updating Composer
Running `php composer.phar self-update` or equivalent will update a phar
install to the latest version.
-
Community
---------
@@ -56,7 +55,7 @@ For support, Stack Overflow also offers a good collection of
[Composer related questions](https://stackoverflow.com/questions/tagged/composer-php).
Please note that this project is released with a
-[Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/).
+[Contributor Code of Conduct](http://contributor-covenant.org/version/1/2/0/).
By participating in this project and its community you agree to abide by those terms.
Requirements
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 000000000..efc7c624e
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,33 @@
+build: false
+shallow_clone: true
+platform: x86
+clone_folder: c:\projects\composer
+
+cache:
+ - c:\tools\php -> appveyor.yml
+
+init:
+ - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;%PATH%
+ - SET COMPOSER_NO_INTERACTION=1
+ - SET PHP=1
+ - SET ANSICON=121x90 (121x90)
+
+install:
+ - IF EXIST c:\tools\php (SET PHP=0)
+ - IF %PHP%==1 cinst -y OpenSSL.Light
+ - IF %PHP%==1 cinst -y php
+ - cd c:\tools\php
+ - IF %PHP%==1 copy php.ini-production php.ini /Y
+ - IF %PHP%==1 echo date.timezone="UTC" >> php.ini
+ - IF %PHP%==1 echo extension_dir=ext >> php.ini
+ - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
+ - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini
+ - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini
+ - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat
+ - appveyor DownloadFile https://getcomposer.org/composer.phar
+ - cd c:\projects\composer
+ - composer install --prefer-source --no-progress
+
+test_script:
+ - cd c:\projects\composer
+ - vendor/bin/phpunit --colors=always
diff --git a/bin/update-spdx-licenses b/bin/update-spdx-licenses
deleted file mode 100644
index e509ded93..000000000
--- a/bin/update-spdx-licenses
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env php
-update();
diff --git a/composer.json b/composer.json
index ffac4f254..b4e372ac4 100644
--- a/composer.json
+++ b/composer.json
@@ -23,11 +23,14 @@
},
"require": {
"php": ">=5.3.2",
- "justinrainbow/json-schema": "~1.4",
+ "justinrainbow/json-schema": "^1.4.4",
+ "composer/spdx-licenses": "^1.0",
+ "composer/semver": "^1.0",
"seld/jsonlint": "~1.0",
"symfony/console": "~2.5",
"symfony/finder": "~2.2",
"symfony/process": "~2.1",
+ "symfony/filesystem": "~2.5",
"seld/phar-utils": "~1.0",
"seld/cli-prompt": "~1.0"
},
@@ -35,7 +38,7 @@
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0"
},
- "_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223",
+ "_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - needs hhvm 3.8+ on travis",
"config": {
"platform": {
"php": "5.3.3"
diff --git a/composer.lock b/composer.lock
index b45ec64a2..8edea7f7d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,24 +4,146 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "556ac817fc0b456bddc48918ef09930d",
+ "hash": "af3956ae4c1a09e3e72cd66346a6176d",
+ "content-hash": "96817117d0ca449e7deff55c98eb7bdc",
"packages": [
{
- "name": "justinrainbow/json-schema",
- "version": "1.4.1",
+ "name": "composer/semver",
+ "version": "1.0.0",
"source": {
"type": "git",
- "url": "https://github.com/justinrainbow/json-schema.git",
- "reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3"
+ "url": "https://github.com/composer/semver.git",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2465fe486c864e30badaa4d005ebdf89dbc503f3",
- "reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3",
+ "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "~2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com"
+ },
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "time": "2015-09-21 09:42:36"
+ },
+ {
+ "name": "composer/spdx-licenses",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/spdx-licenses.git",
+ "reference": "324b3530ac3e6277ff4bedf82a34fbf35836eb8d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/324b3530ac3e6277ff4bedf82a34fbf35836eb8d",
+ "reference": "324b3530ac3e6277ff4bedf82a34fbf35836eb8d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "~2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Spdx\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com"
+ },
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "SPDX licenses list and validation library.",
+ "keywords": [
+ "license",
+ "spdx",
+ "validator"
+ ],
+ "time": "2015-09-07 16:25:20"
+ },
+ {
+ "name": "justinrainbow/json-schema",
+ "version": "1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/justinrainbow/json-schema.git",
+ "reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
+ "reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
},
"require-dev": {
"json-schema/json-schema-test-suite": "1.1.0",
@@ -38,8 +160,8 @@
}
},
"autoload": {
- "psr-0": {
- "JsonSchema": "src/"
+ "psr-4": {
+ "JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -70,7 +192,7 @@
"json",
"schema"
],
- "time": "2015-03-27 16:41:39"
+ "time": "2015-09-08 22:28:04"
},
{
"name": "seld/cli-prompt",
@@ -212,17 +334,17 @@
},
{
"name": "symfony/console",
- "version": "v2.6.9",
+ "version": "v2.6.11",
"target-dir": "Symfony/Component/Console",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
- "reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd"
+ "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Console/zipball/b5ec0c11a204718f2b656357f5505a8e578f30dd",
- "reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd",
+ "url": "https://api.github.com/repos/symfony/Console/zipball/0e5e18ae09d3f5c06367759be940e9ed3f568359",
+ "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359",
"shasum": ""
},
"require": {
@@ -266,21 +388,71 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2015-05-29 14:42:58"
+ "time": "2015-07-26 09:08:40"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v2.6.11",
+ "target-dir": "Symfony/Component/Filesystem",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Filesystem.git",
+ "reference": "823c035b1a5c13a4924e324d016eb07e70f94735"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Filesystem/zipball/823c035b1a5c13a4924e324d016eb07e70f94735",
+ "reference": "823c035b1a5c13a4924e324d016eb07e70f94735",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Filesystem\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Filesystem Component",
+ "homepage": "https://symfony.com",
+ "time": "2015-07-08 05:59:48"
},
{
"name": "symfony/finder",
- "version": "v2.6.9",
+ "version": "v2.6.11",
"target-dir": "Symfony/Component/Finder",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
- "reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14"
+ "reference": "203a10f928ae30176deeba33512999233181dd28"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Finder/zipball/ffedd3e0ff8155188155e9322fe21b9ee012ac14",
- "reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/203a10f928ae30176deeba33512999233181dd28",
+ "reference": "203a10f928ae30176deeba33512999233181dd28",
"shasum": ""
},
"require": {
@@ -316,21 +488,21 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2015-05-15 13:32:45"
+ "time": "2015-07-09 16:02:48"
},
{
"name": "symfony/process",
- "version": "v2.6.9",
+ "version": "v2.6.11",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
- "reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306"
+ "reference": "57f1e88bb5dafa449b83f9f265b11d52d517b3e9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Process/zipball/7856d78ab6cce6e59d02d9e1a873441f6bd21306",
- "reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/57f1e88bb5dafa449b83f9f265b11d52d517b3e9",
+ "reference": "57f1e88bb5dafa449b83f9f265b11d52d517b3e9",
"shasum": ""
},
"require": {
@@ -366,22 +538,22 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2015-05-15 13:32:45"
+ "time": "2015-06-30 16:10:16"
}
],
"packages-dev": [
{
"name": "doctrine/instantiator",
- "version": "1.0.4",
+ "version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
- "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
@@ -392,7 +564,7 @@
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "~4.0",
- "squizlabs/php_codesniffer": "2.0.*@ALPHA"
+ "squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"extra": {
@@ -401,8 +573,8 @@
}
},
"autoload": {
- "psr-0": {
- "Doctrine\\Instantiator\\": "src"
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -422,7 +594,7 @@
"constructor",
"instantiate"
],
- "time": "2014-10-13 12:58:55"
+ "time": "2015-06-14 21:17:01"
},
{
"name": "phpdocumentor/reflection-docblock",
@@ -475,16 +647,16 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.4.1",
+ "version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
+ "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
- "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
+ "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
"shasum": ""
},
"require": {
@@ -531,20 +703,20 @@
"spy",
"stub"
],
- "time": "2015-04-27 22:15:08"
+ "time": "2015-08-13 10:07:40"
},
{
"name": "phpunit/php-code-coverage",
- "version": "2.1.5",
+ "version": "2.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "be2286cb8c7e1773eded49d9719219e6f74f9e3e"
+ "reference": "2d7c03c0e4e080901b8f33b2897b0577be18a13c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/be2286cb8c7e1773eded49d9719219e6f74f9e3e",
- "reference": "be2286cb8c7e1773eded49d9719219e6f74f9e3e",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2d7c03c0e4e080901b8f33b2897b0577be18a13c",
+ "reference": "2d7c03c0e4e080901b8f33b2897b0577be18a13c",
"shasum": ""
},
"require": {
@@ -552,7 +724,7 @@
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
- "sebastian/environment": "~1.0",
+ "sebastian/environment": "^1.3.2",
"sebastian/version": "~1.0"
},
"require-dev": {
@@ -567,7 +739,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1.x-dev"
+ "dev-master": "2.2.x-dev"
}
},
"autoload": {
@@ -593,20 +765,20 @@
"testing",
"xunit"
],
- "time": "2015-06-09 13:05:42"
+ "time": "2015-08-04 03:42:39"
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.4.0",
+ "version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
- "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"shasum": ""
},
"require": {
@@ -640,20 +812,20 @@
"filesystem",
"iterator"
],
- "time": "2015-04-02 05:19:05"
+ "time": "2015-06-21 13:08:43"
},
{
"name": "phpunit/php-text-template",
- "version": "1.2.0",
+ "version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
- "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"shasum": ""
},
"require": {
@@ -662,20 +834,17 @@
"type": "library",
"autoload": {
"classmap": [
- "Text/"
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
- "include-path": [
- ""
- ],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -684,20 +853,20 @@
"keywords": [
"template"
],
- "time": "2014-01-30 17:20:04"
+ "time": "2015-06-21 13:50:34"
},
{
"name": "phpunit/php-timer",
- "version": "1.0.5",
+ "version": "1.0.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
- "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"shasum": ""
},
"require": {
@@ -706,13 +875,10 @@
"type": "library",
"autoload": {
"classmap": [
- "PHP/"
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
- "include-path": [
- ""
- ],
"license": [
"BSD-3-Clause"
],
@@ -728,20 +894,20 @@
"keywords": [
"timer"
],
- "time": "2013-08-02 07:42:54"
+ "time": "2015-06-21 08:01:12"
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.1",
+ "version": "1.4.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "eab81d02569310739373308137284e0158424330"
+ "reference": "3ab72c62e550370a6cd5dc873e1a04ab57562f5b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
- "reference": "eab81d02569310739373308137284e0158424330",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3ab72c62e550370a6cd5dc873e1a04ab57562f5b",
+ "reference": "3ab72c62e550370a6cd5dc873e1a04ab57562f5b",
"shasum": ""
},
"require": {
@@ -777,20 +943,20 @@
"keywords": [
"tokenizer"
],
- "time": "2015-04-08 04:46:07"
+ "time": "2015-08-16 08:51:00"
},
{
"name": "phpunit/phpunit",
- "version": "4.7.2",
+ "version": "4.8.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "8e0c63329c8c4185296b8d357daa5c6bae43080f"
+ "reference": "2246830f4a1a551c67933e4171bf2126dc29d357"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e0c63329c8c4185296b8d357daa5c6bae43080f",
- "reference": "8e0c63329c8c4185296b8d357daa5c6bae43080f",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2246830f4a1a551c67933e4171bf2126dc29d357",
+ "reference": "2246830f4a1a551c67933e4171bf2126dc29d357",
"shasum": ""
},
"require": {
@@ -800,15 +966,15 @@
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
- "phpspec/prophecy": "~1.3,>=1.3.1",
+ "phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "~2.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
- "phpunit/php-timer": "~1.0",
+ "phpunit/php-timer": ">=1.0.6",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
- "sebastian/environment": "~1.2",
+ "sebastian/environment": "~1.3",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/version": "~1.0",
@@ -823,7 +989,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.7.x-dev"
+ "dev-master": "4.8.x-dev"
}
},
"autoload": {
@@ -849,7 +1015,7 @@
"testing",
"xunit"
],
- "time": "2015-06-06 08:36:08"
+ "time": "2015-08-24 04:09:38"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -908,16 +1074,16 @@
},
{
"name": "sebastian/comparator",
- "version": "1.1.1",
+ "version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "1dd8869519a225f7f2b9eb663e225298fade819e"
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e",
- "reference": "1dd8869519a225f7f2b9eb663e225298fade819e",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
"shasum": ""
},
"require": {
@@ -931,7 +1097,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1.x-dev"
+ "dev-master": "1.2.x-dev"
}
},
"autoload": {
@@ -968,7 +1134,7 @@
"compare",
"equality"
],
- "time": "2015-01-29 16:28:08"
+ "time": "2015-07-26 15:48:44"
},
{
"name": "sebastian/diff",
@@ -1024,16 +1190,16 @@
},
{
"name": "sebastian/environment",
- "version": "1.2.2",
+ "version": "1.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
+ "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
- "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44",
+ "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44",
"shasum": ""
},
"require": {
@@ -1070,20 +1236,20 @@
"environment",
"hhvm"
],
- "time": "2015-01-01 10:01:08"
+ "time": "2015-08-03 06:14:51"
},
{
"name": "sebastian/exporter",
- "version": "1.2.0",
+ "version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "84839970d05254c73cde183a721c7af13aede943"
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943",
- "reference": "84839970d05254c73cde183a721c7af13aede943",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
"shasum": ""
},
"require": {
@@ -1136,7 +1302,7 @@
"export",
"exporter"
],
- "time": "2015-01-27 07:23:06"
+ "time": "2015-06-21 07:55:53"
},
{
"name": "sebastian/global-state",
@@ -1191,16 +1357,16 @@
},
{
"name": "sebastian/recursion-context",
- "version": "1.0.0",
+ "version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "3989662bbb30a29d20d9faa04a846af79b276252"
+ "reference": "994d4a811bafe801fb06dccbee797863ba2792ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252",
- "reference": "3989662bbb30a29d20d9faa04a846af79b276252",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/994d4a811bafe801fb06dccbee797863ba2792ba",
+ "reference": "994d4a811bafe801fb06dccbee797863ba2792ba",
"shasum": ""
},
"require": {
@@ -1240,20 +1406,20 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2015-01-24 09:48:32"
+ "time": "2015-06-21 08:04:50"
},
{
"name": "sebastian/version",
- "version": "1.0.5",
+ "version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
- "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
"shasum": ""
},
"type": "library",
@@ -1275,21 +1441,21 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2015-02-24 06:35:25"
+ "time": "2015-06-21 13:59:46"
},
{
"name": "symfony/yaml",
- "version": "v2.6.9",
+ "version": "v2.6.11",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
- "reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2"
+ "reference": "c044d1744b8e91aaaa0d9bac683ab87ec7cbf359"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Yaml/zipball/f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
- "reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/c044d1744b8e91aaaa0d9bac683ab87ec7cbf359",
+ "reference": "c044d1744b8e91aaaa0d9bac683ab87ec7cbf359",
"shasum": ""
},
"require": {
@@ -1325,7 +1491,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2015-05-02 15:18:45"
+ "time": "2015-07-26 08:59:42"
}
],
"aliases": [],
diff --git a/doc/00-intro.md b/doc/00-intro.md
index 0496390ca..d984eb7b9 100644
--- a/doc/00-intro.md
+++ b/doc/00-intro.md
@@ -1,54 +1,41 @@
# Introduction
Composer is a tool for dependency management in PHP. It allows you to declare
-the dependent libraries your project needs and it will install them in your
-project for you.
+the libraries your project depends on and it will manage (install/update) them
+for you.
## Dependency management
-Composer is not a package manager. Yes, it deals with "packages" or libraries, but
-it manages them on a per-project basis, installing them in a directory (e.g. `vendor`)
-inside your project. By default it will never install anything globally. Thus,
-it is a dependency manager.
+Composer is **not** a package manager in the same sense as Yum or Apt are. Yes,
+it deals with "packages" or libraries, but it manages them on a per-project
+basis, installing them in a directory (e.g. `vendor`) inside your project. By
+default it will never install anything globally. Thus, it is a dependency
+manager.
-This idea is not new and Composer is strongly inspired by node's [npm](https://npmjs.org/)
-and ruby's [bundler](http://bundler.io/). But there has not been such a tool
-for PHP.
+This idea is not new and Composer is strongly inspired by node's
+[npm](https://npmjs.org/) and ruby's [bundler](http://bundler.io/).
-The problem that Composer solves is this:
+Suppose:
a) You have a project that depends on a number of libraries.
b) Some of those libraries depend on other libraries.
-c) You declare the things you depend on.
+Composer:
-d) Composer finds out which versions of which packages need to be installed, and
+c) Enables you to declare the libraries you depend on.
+
+d) Finds out which versions of which packages can and need to be installed, and
installs them (meaning it downloads them into your project).
-## Declaring dependencies
-
-Let's say you are creating a project, and you need a library that does logging.
-You decide to use [monolog](https://github.com/Seldaek/monolog). In order to
-add it to your project, all you need to do is create a `composer.json` file
-which describes the project's dependencies.
-
-```json
-{
- "require": {
- "monolog/monolog": "1.2.*"
- }
-}
-```
-
-We are simply stating that our project requires some `monolog/monolog` package,
-any version beginning with `1.2`.
+See the [Basic usage](01-basic-usage.md) chapter for more details on declaring
+dependencies.
## System Requirements
Composer requires PHP 5.3.2+ to run. A few sensitive php settings and compile
-flags are also required, but when using the installer you will be warned about any
-incompatibilities.
+flags are also required, but when using the installer you will be warned about
+any incompatibilities.
To install packages from sources instead of simple zip archives, you will need
git, svn or hg depending on how the package is version-controlled.
@@ -60,6 +47,12 @@ Linux and OSX.
### Downloading the Composer Executable
+Composer offers a convenient installer that you can execute directly from the
+commandline. Feel free to [download this file](https://getcomposer.org/installer)
+or review it on [GitHub](https://github.com/composer/getcomposer.org/blob/master/web/installer)
+if you wish to know more about the inner workings of the installer. The source
+is plain PHP.
+
There are in short, two ways to install Composer. Locally as part of your
project, or globally as a system wide executable.
@@ -79,37 +72,54 @@ curl -sS https://getcomposer.org/installer | php
php -r "readfile('https://getcomposer.org/installer');" | php
```
-The installer will just check a few PHP settings and then download `composer.phar`
-to your working directory. This file is the Composer binary. It is a PHAR (PHP
-archive), which is an archive format for PHP which can be run on the command
-line, amongst other things.
+The installer will just check a few PHP settings and then download
+`composer.phar` to your working directory. This file is the Composer binary. It
+is a PHAR (PHP archive), which is an archive format for PHP which can be run on
+the command line, amongst other things.
+
+Now just run `php composer.phar` in order to run Composer.
You can install Composer to a specific directory by using the `--install-dir`
-option and providing a target directory (it can be an absolute or relative path):
+option and additionally (re)name it as well using the `--filename` option:
```sh
-curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
+curl -sS https://getcomposer.org/installer | php -- --install-dir=bin --filename=composer
```
+Now just run `php bin/composer` in order to run Composer.
+
#### Globally
-You can place this file anywhere you wish. If you put it in your `PATH`,
-you can access it globally. On unixy systems you can even make it
-executable and invoke it without `php`.
+You can place the Composer PHAR anywhere you wish. If you put it in a directory
+that is part of your `PATH`, you can access it globally. On unixy systems you
+can even make it executable and invoke it without directly using the `php`
+interpreter.
-You can run these commands to easily access `composer` from anywhere on your system:
+Run these commands to globally install `composer` on your system:
```sh
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
-> **Note:** If the above fails due to permissions, run the `mv` line
-> again with sudo.
+> **Note:** If the above fails due to permissions, run the `mv` line again
+> with sudo.
-> **Note:** In OSX Yosemite the `/usr` directory does not exist by default. If you receive the error "/usr/local/bin/composer: No such file or directory" then you must create `/usr/local/bin/` manually before proceeding.
+A quick copy-paste version including sudo:
-Then, just run `composer` in order to run Composer instead of `php composer.phar`.
+```sh
+curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
+```
+
+> **Note:** On some versions of OSX the `/usr` directory does not exist by
+> default. If you receive the error "/usr/local/bin/composer: No such file or
+> directory" then you must create the directory manually before proceeding:
+> `mkdir -p /usr/local/bin`.
+
+> **Note:** For information on changing your PATH, please read the
+> [Wikipedia article](https://en.wikipedia.org/wiki/PATH_(variable)) and/or use Google.
+
+Now just run `composer` in order to run Composer instead of `php composer.phar`.
## Installation - Windows
@@ -117,24 +127,26 @@ Then, just run `composer` in order to run Composer instead of `php composer.phar
This is the easiest way to get Composer set up on your machine.
-Download and run [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe),
-it will install the latest Composer version and set up your PATH so that you can
-just call `composer` from any directory in your command line.
+Download and run
+[Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe). It will
+install the latest Composer version and set up your PATH so that you can just
+call `composer` from any directory in your command line.
-> **Note:** Close your current terminal. Test usage with a new terminal:
-> That is important since the PATH only gets loaded when the terminal starts.
+> **Note:** Close your current terminal. Test usage with a new terminal: This is
+> important since the PATH only gets loaded when the terminal starts.
### Manual Installation
Change to a directory on your `PATH` and run the install snippet to download
-composer.phar:
+`composer.phar`:
```sh
C:\Users\username>cd C:\bin
C:\bin>php -r "readfile('https://getcomposer.org/installer');" | php
```
-> **Note:** If the above fails due to readfile, use the `http` url or enable php_openssl.dll in php.ini
+> **Note:** If the above fails due to readfile, use the `http` url or enable
+> php_openssl.dll in php.ini
Create a new `composer.bat` file alongside `composer.phar`:
@@ -153,38 +165,7 @@ Composer version 27d8904
## Using Composer
-We will now use Composer to install the dependencies of the project. If you
-don't have a `composer.json` file in the current directory please skip to the
-[Basic Usage](01-basic-usage.md) chapter.
+Now that you've installed Composer, you are ready to use it! Head on over to the
+next chapter for a short and simple demonstration.
-To resolve and download dependencies, run the `install` command:
-
-```sh
-php composer.phar install
-```
-
-If you did a global install and do not have the phar in that directory
-run this instead:
-
-```sh
-composer install
-```
-
-Following the [example above](#declaring-dependencies), this will download
-monolog into the `vendor/monolog/monolog` directory.
-
-## Autoloading
-
-Besides downloading the library, Composer also prepares an autoload file that's
-capable of autoloading all of the classes in any of the libraries that it
-downloads. To use it, just add the following line to your code's bootstrap
-process:
-
-```php
-require __DIR__ . '/vendor/autoload.php';
-```
-
-Woah! Now start using monolog! To keep learning more about Composer, keep
-reading the "Basic Usage" chapter.
-
-[Basic Usage](01-basic-usage.md) →
+[Basic usage](01-basic-usage.md) →
diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md
index 3d4f2b77d..b33f06ac6 100644
--- a/doc/01-basic-usage.md
+++ b/doc/01-basic-usage.md
@@ -1,8 +1,13 @@
# Basic usage
-## Installing
+## Introduction
-If you have not yet installed Composer, refer to the [Intro](00-intro.md) chapter.
+For our basic usage introduction, we will be installing `monolog/monolog`,
+a logging library. If you have not yet installed Composer, refer to the
+[Intro](00-intro.md) chapter.
+
+> **Note:** for the sake of simplicity, this introduction will assume you
+> have performed a [local](00-intro.md#locally) install of Composer.
## `composer.json`: Project Setup
@@ -10,14 +15,11 @@ To start using Composer in your project, all you need is a `composer.json`
file. This file describes the dependencies of your project and may contain
other metadata as well.
-The [JSON format](http://json.org/) is quite easy to write. It allows you to
-define nested structures.
-
### The `require` Key
The first (and often only) thing you specify in `composer.json` is the
-`require` key. You're simply telling Composer which packages your project
-depends on.
+[`require`](04-schema.md#require) key. You're simply telling Composer which
+packages your project depends on.
```json
{
@@ -27,15 +29,16 @@ depends on.
}
```
-As you can see, `require` takes an object that maps **package names** (e.g. `monolog/monolog`)
-to **package versions** (e.g. `1.0.*`).
+As you can see, [`require`](04-schema.md#require) takes an object that maps
+**package names** (e.g. `monolog/monolog`) to **version constraints** (e.g.
+`1.0.*`).
### Package Names
The package name consists of a vendor name and the project's name. Often these
-will be identical - the vendor name just exists to prevent naming clashes. It allows
-two different people to create a library named `json`, which would then just be
-named `igorw/json` and `seldaek/json`.
+will be identical - the vendor name just exists to prevent naming clashes. It
+allows two different people to create a library named `json`, which would then
+just be named `igorw/json` and `seldaek/json`.
Here we are requiring `monolog/monolog`, so the vendor name is the same as the
project's name. For projects with a unique name this is recommended. It also
@@ -45,66 +48,26 @@ smaller decoupled parts.
### Package Versions
-In the previous example we were requiring version [`1.0.*`](http://semver.mwl.be/#?package=monolog%2Fmonolog&version=1.0.*) of monolog. This
-means any version in the `1.0` development branch. It would match `1.0.0`,
-`1.0.2` or `1.0.20`.
+In the previous example we were requiring version
+[`1.0.*`](http://semver.mwl.be/#?package=monolog%2Fmonolog&version=1.0.*) of
+Monolog. This means any version in the `1.0` development branch. It is the
+equivalent of saying versions that match `>=1.0 <1.1`.
-Version constraints can be specified in a few different ways.
-
-Name | Example | Description
--------------- | ------------------------------------------------------------------------ | -----------
-Exact version | `1.0.2` | You can specify the exact version of a package.
-Range | `>=1.0` `>=1.0 <2.0` >=1.0 <1.1 || >=1.2
| By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`.
You can define multiple ranges. Ranges separated by a space (
) or comma (`,`) will be treated as a **logical AND**. A double pipe (||
) will be treated as a **logical OR**. AND has higher precedence than OR.
-Hyphen Range | `1.0 - 2.0` | Inclusive set of versions. Partial versions on the right include are completed with a wildcard. For example `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` as the `2.0` becomes `2.0.*`. On the other hand `1.0.0 - 2.1.0` is equivalent to `>=1.0.0 <=2.1.0`.
-Wildcard | `1.0.*` | You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of `>=1.0 <1.1`.
-Tilde Operator | `~1.2` | Very useful for projects that follow semantic versioning. `~1.2` is equivalent to `>=1.2 <2.0`. For more details, read the next section below.
-Caret Operator | `^1.2.3` | Very useful for projects that follow semantic versioning. `^1.2.3` is equivalent to `>=1.2.3 <2.0`. For more details, read the next section below.
-
-### Next Significant Release (Tilde and Caret Operators)
-
-The `~` operator is best explained by example: `~1.2` is equivalent to
-`>=1.2 <2.0.0`, while `~1.2.3` is equivalent to `>=1.2.3 <1.3.0`. As you can see
-it is mostly useful for projects respecting [semantic
-versioning](http://semver.org/). A common usage would be to mark the minimum
-minor version you depend on, like `~1.2` (which allows anything up to, but not
-including, 2.0). Since in theory there should be no backwards compatibility
-breaks until 2.0, that works well. Another way of looking at it is that using
-`~` specifies a minimum version, but allows the last digit specified to go up.
-
-The `^` operator behaves very similarly but it sticks closer to semantic
-versioning, and will always allow non-breaking updates. For example `^1.2.3`
-is equivalent to `>=1.2.3 <2.0.0` as none of the releases until 2.0 should
-break backwards compatibility. For pre-1.0 versions it also acts with safety
-in mind and treats `^0.3` as `>=0.3.0 <0.4.0`
-
-> **Note:** Though `2.0-beta.1` is strictly before `2.0`, a version constraint
-> like `~1.2` would not install it. As said above `~1.2` only means the `.2`
-> can change but the `1.` part is fixed.
-
-> **Note:** The `~` operator has an exception on its behavior for the major
-> release number. This means for example that `~1` is the same as `~1.0` as
-> it will not allow the major number to increase trying to keep backwards
-> compatibility.
+Version constraints can be specified in several ways, read
+[versions](articles/versions.md) for more in-depth information on this topic.
### Stability
-By default only stable releases are taken into consideration. If you would like
-to also get RC, beta, alpha or dev versions of your dependencies you can do
-so using [stability flags](04-schema.md#package-links). To change that for all
-packages instead of doing per dependency you can also use the
+By default only stable releases are taken into consideration. If you would
+like to also get RC, beta, alpha or dev versions of your dependencies you can
+do so using [stability flags](04-schema.md#package-links). To change that for
+all packages instead of doing per dependency you can also use the
[minimum-stability](04-schema.md#minimum-stability) setting.
-### Test version constraints
-
-You can test version constraints using [semver.mwl.be](http://semver.mwl.be). Fill in
-a package name and it will autofill the default version constraint which Composer would add
-to your `composer.json` file. You can adjust the version constraint and the tool will highlight
-all releases that match.
-
## Installing Dependencies
-To fetch the defined dependencies into your local project, just run the
-`install` command of `composer.phar`.
+To install the defined dependencies for your project, just run the
+[`install`](03-cli.md#install) command.
```sh
php composer.phar install
@@ -113,14 +76,14 @@ php composer.phar install
This will find the latest version of `monolog/monolog` that matches the
supplied version constraint and download it into the `vendor` directory.
It's a convention to put third party code into a directory named `vendor`.
-In case of monolog it will put it into `vendor/monolog/monolog`.
+In case of Monolog it will put it into `vendor/monolog/monolog`.
> **Tip:** If you are using git for your project, you probably want to add
-> `vendor` into your `.gitignore`. You really don't want to add all of that
+> `vendor` in your `.gitignore`. You really don't want to add all of that
> code to your repository.
-Another thing that the `install` command does is it adds a `composer.lock`
-file into your project root.
+You will notice the [`install`](03-cli.md#install) command also created a
+`composer.lock` file.
## `composer.lock` - The Lock File
@@ -128,82 +91,82 @@ After installing the dependencies, Composer writes the list of the exact
versions it installed into a `composer.lock` file. This locks the project
to those specific versions.
-**Commit your application's `composer.lock` (along with `composer.json`) into version control.**
+**Commit your application's `composer.lock` (along with `composer.json`)
+into version control.**
-This is important because the `install` command checks if a lock file is present,
-and if it is, it downloads the versions specified there (regardless of what `composer.json`
-says).
+This is important because the [`install`](03-cli.md#install) command checks
+if a lock file is present, and if it is, it downloads the versions specified
+there (regardless of what `composer.json` says).
-This means that anyone who sets up the project will download the exact
-same version of the dependencies. Your CI server, production machines, other
-developers in your team, everything and everyone runs on the same dependencies, which
-mitigates the potential for bugs affecting only some parts of the deployments. Even if you
-develop alone, in six months when reinstalling the project you can feel confident the
-dependencies installed are still working even if your dependencies released
-many new versions since then.
+This means that anyone who sets up the project will download the exact same
+version of the dependencies. Your CI server, production machines, other
+developers in your team, everything and everyone runs on the same dependencies,
+which mitigates the potential for bugs affecting only some parts of the
+deployments. Even if you develop alone, in six months when reinstalling the
+project you can feel confident the dependencies installed are still working even
+if your dependencies released many new versions since then.
If no `composer.lock` file exists, Composer will read the dependencies and
-versions from `composer.json` and create the lock file after executing the `update` or the `install`
-command.
+versions from `composer.json` and create the lock file after executing the
+[`update`](03-cli.md#update) or the [`install`](03-cli.md#install) command.
-This means that if any of the dependencies get a new version, you won't get the updates
-automatically. To update to the new version, use the `update` command. This will fetch
-the latest matching versions (according to your `composer.json` file) and also update
-the lock file with the new version.
+This means that if any of the dependencies get a new version, you won't get the
+updates automatically. To update to the new version, use the
+[`update`](03-cli.md#update) command. This will fetch the latest matching
+versions (according to your `composer.json` file) and also update the lock file
+with the new version.
```sh
php composer.phar update
```
-> **Note:** Composer will display a Warning when executing an `install` command if
- `composer.lock` and `composer.json` are not synchronized.
-
+> **Note:** Composer will display a Warning when executing an `install` command
+> if `composer.lock` and `composer.json` are not synchronized.
+
If you only want to install or update one dependency, you can whitelist them:
```sh
php composer.phar update monolog/monolog [...]
```
-> **Note:** For libraries it is not necessarily recommended to commit the lock file,
-> see also: [Libraries - Lock file](02-libraries.md#lock-file).
+> **Note:** For libraries it is not necessary to commit the lock
+> file, see also: [Libraries - Lock file](02-libraries.md#lock-file).
## Packagist
[Packagist](https://packagist.org/) is the main Composer repository. A Composer
repository is basically a package source: a place where you can get packages
from. Packagist aims to be the central repository that everybody uses. This
-means that you can automatically `require` any package that is available
-there.
+means that you can automatically `require` any package that is available there.
-If you go to the [packagist website](https://packagist.org/) (packagist.org),
+If you go to the [Packagist website](https://packagist.org/) (packagist.org),
you can browse and search for packages.
-Any open source project using Composer should publish their packages on
-packagist. A library doesn't need to be on packagist to be used by Composer,
-but it makes life quite a bit simpler.
+Any open source project using Composer is recommended to publish their packages
+on Packagist. A library doesn't need to be on Packagist to be used by Composer,
+but it enables discovery and adoption by other developers more quickly.
## Autoloading
For libraries that specify autoload information, Composer generates a
-`vendor/autoload.php` file. You can simply include this file and you
-will get autoloading for free.
+`vendor/autoload.php` file. You can simply include this file and you will get
+autoloading for free.
```php
-require 'vendor/autoload.php';
+require __DIR__ . '/vendor/autoload.php';
```
-This makes it really easy to use third party code. For example: If your
-project depends on monolog, you can just start using classes from it, and they
-will be autoloaded.
+This makes it really easy to use third party code. For example: If your project
+depends on Monolog, you can just start using classes from it, and they will be
+autoloaded.
```php
$log = new Monolog\Logger('name');
$log->pushHandler(new Monolog\Handler\StreamHandler('app.log', Monolog\Logger::WARNING));
-
$log->addWarning('Foo');
```
-You can even add your own code to the autoloader by adding an `autoload` field
-to `composer.json`.
+You can even add your own code to the autoloader by adding an
+[`autoload`](04-schema.md#autoload) field to `composer.json`.
```json
{
@@ -220,24 +183,25 @@ You define a mapping from namespaces to directories. The `src` directory would
be in your project root, on the same level as `vendor` directory is. An example
filename would be `src/Foo.php` containing an `Acme\Foo` class.
-After adding the `autoload` field, you have to re-run `dump-autoload` to re-generate
-the `vendor/autoload.php` file.
+After adding the [`autoload`](04-schema.md#autoload) field, you have to re-run
+[`dump-autoload`](03-cli.md#dump-autoload) to re-generate the
+`vendor/autoload.php` file.
Including that file will also return the autoloader instance, so you can store
the return value of the include call in a variable and add more namespaces.
This can be useful for autoloading classes in a test suite, for example.
```php
-$loader = require 'vendor/autoload.php';
+$loader = require __DIR__ . '/vendor/autoload.php';
$loader->add('Acme\\Test\\', __DIR__);
```
-In addition to PSR-4 autoloading, classmap is also supported. This allows
-classes to be autoloaded even if they do not conform to PSR-4. See the
-[autoload reference](04-schema.md#autoload) for more details.
+In addition to PSR-4 autoloading, Composer also supports PSR-0, classmap and
+files autoloading. See the [`autoload`](04-schema.md#autoload) reference for
+more information.
-> **Note:** Composer provides its own autoloader. If you don't want to use
-that one, you can just include `vendor/composer/autoload_*.php` files,
-which return associative arrays allowing you to configure your own autoloader.
+> **Note:** Composer provides its own autoloader. If you don't want to use that
+> one, you can just include `vendor/composer/autoload_*.php` files, which return
+> associative arrays allowing you to configure your own autoloader.
← [Intro](00-intro.md) | [Libraries](02-libraries.md) →
diff --git a/doc/02-libraries.md b/doc/02-libraries.md
index 0749ac53f..da5725e4d 100644
--- a/doc/02-libraries.md
+++ b/doc/02-libraries.md
@@ -1,16 +1,17 @@
# Libraries
-This chapter will tell you how to make your library installable through Composer.
+This chapter will tell you how to make your library installable through
+Composer.
## Every project is a package
As soon as you have a `composer.json` in a directory, that directory is a
-package. When you add a `require` to a project, you are making a package that
-depends on other packages. The only difference between your project and
-libraries is that your project is a package without a name.
+package. When you add a [`require`](04-schema.md#require) to a project, you are
+making a package that depends on other packages. The only difference between
+your project and libraries is that your project is a package without a name.
In order to make that package installable you need to give it a name. You do
-this by adding a `name` to `composer.json`:
+this by adding the [`name`](04-schema.md#name) property in `composer.json`:
```json
{
@@ -21,12 +22,12 @@ this by adding a `name` to `composer.json`:
}
```
-In this case the project name is `acme/hello-world`, where `acme` is the
-vendor name. Supplying a vendor name is mandatory.
+In this case the project name is `acme/hello-world`, where `acme` is the vendor
+name. Supplying a vendor name is mandatory.
> **Note:** If you don't know what to use as a vendor name, your GitHub
-username is usually a good bet. While package names are case insensitive, the
-convention is all lowercase and dashes for word separation.
+> username is usually a good bet. While package names are case insensitive, the
+> convention is all lowercase and dashes for word separation.
## Platform packages
@@ -50,15 +51,14 @@ includes PHP itself, PHP extensions and some system libraries.
PHP. The following are available: `curl`, `iconv`, `icu`, `libxml`,
`openssl`, `pcre`, `uuid`, `xsl`.
-You can use `composer show --platform` to get a list of your locally available
-platform packages.
+You can use [`show --platform`](03-cli.md#show) to get a list of your locally
+available platform packages.
## Specifying the version
-You need to specify the package's version some way. When you publish your
-package on Packagist, it is able to infer the version from the VCS (git, svn,
-hg) information, so in that case you do not have to specify it, and it is
-recommended not to. See [tags](#tags) and [branches](#branches) to see how
+When you publish your package on Packagist, it is able to infer the version
+from the VCS (git, svn, hg) information. This means you don't have to
+explicitly declare it. Read [tags](#tags) and [branches](#branches) to see how
version numbers are extracted from these.
If you are creating packages by hand and really have to specify it explicitly,
@@ -76,9 +76,9 @@ you can just add a `version` field:
### Tags
For every tag that looks like a version, a package version of that tag will be
-created. It should match 'X.Y.Z' or 'vX.Y.Z', with an optional suffix
-of `-patch` (`-p`), `-alpha` (`-a`), `-beta` (`-b`) or `-RC`. The suffixes
-can also be followed by a number.
+created. It should match 'X.Y.Z' or 'vX.Y.Z', with an optional suffix of
+`-patch` (`-p`), `-alpha` (`-a`), `-beta` (`-b`) or `-RC`. The suffix can also
+be followed by a number.
Here are a few examples of valid tag names:
@@ -89,19 +89,20 @@ Here are a few examples of valid tag names:
- v2.0.0-alpha
- v2.0.4-p1
-> **Note:** Even if your tag is prefixed with `v`, a [version constraint](01-basic-usage.md#package-versions)
-> in a `require` statement has to be specified without prefix
-> (e.g. tag `v1.0.0` will result in version `1.0.0`).
+> **Note:** Even if your tag is prefixed with `v`, a
+> [version constraint](01-basic-usage.md#package-versions) in a `require`
+> statement has to be specified without prefix (e.g. tag `v1.0.0` will result
+> in version `1.0.0`).
### Branches
For every branch, a package development version will be created. If the branch
name looks like a version, the version will be `{branchname}-dev`. For example,
-the branch `2.0` will get the `2.0.x-dev` version (the `.x` is added for technical
-reasons, to make sure it is recognized as a branch). The `2.0.x` branch would also
-be valid and be turned into `2.0.x-dev` as well. If the branch does not look
-like a version, it will be `dev-{branchname}`. `master` results in a
-`dev-master` version.
+the branch `2.0` will get the `2.0.x-dev` version (the `.x` is added for
+technical reasons, to make sure it is recognized as a branch). The `2.0.x`
+branch would also be valid and be turned into `2.0.x-dev` as well. If the
+branch does not look like a version, it will be `dev-{branchname}`. `master`
+results in a `dev-master` version.
Here are some examples of version branch names:
@@ -116,8 +117,8 @@ Here are some examples of version branch names:
### Aliases
It is possible to alias branch names to versions. For example, you could alias
-`dev-master` to `1.0.x-dev`, which would allow you to require `1.0.x-dev` in all
-the packages.
+`dev-master` to `1.0.x-dev`, which would allow you to require `1.0.x-dev` in
+all the packages.
See [Aliases](articles/aliases.md) for more information.
@@ -133,7 +134,7 @@ the `.gitignore`.
## Publishing to a VCS
-Once you have a vcs repository (version control system, e.g. git) containing a
+Once you have a VCS repository (version control system, e.g. git) containing a
`composer.json` file, your library is already composer-installable. In this
example we will publish the `acme/hello-world` library on GitHub under
`github.com/username/hello-world`.
@@ -180,11 +181,11 @@ For more details on how package repositories work and what other types are
available, see [Repositories](05-repositories.md).
That's all. You can now install the dependencies by running Composer's
-`install` command!
+[`install`](03-cli.md#install) command!
**Recap:** Any git/svn/hg repository containing a `composer.json` can be added
to your project by specifying the package repository and declaring the
-dependency in the `require` field.
+dependency in the [`require`](04-schema.md#require) field.
## Publishing to packagist
@@ -196,15 +197,16 @@ repository for `monolog/monolog`. How did that work? The answer is Packagist.
[Packagist](https://packagist.org/) is the main package repository for
Composer, and it is enabled by default. Anything that is published on
-Packagist is available automatically through Composer. Since monolog
-[is on packagist](https://packagist.org/packages/monolog/monolog), we can depend
-on it without having to specify any additional repositories.
+Packagist is available automatically through Composer. Since
+[Monolog is on Packagist](https://packagist.org/packages/monolog/monolog), we
+can depend on it without having to specify any additional repositories.
If we wanted to share `hello-world` with the world, we would publish it on
Packagist as well. Doing so is really easy.
-You simply hit the big "Submit Package" button and sign up. Then you submit
-the URL to your VCS repository, at which point Packagist will start crawling
-it. Once it is done, your package will be available to anyone.
+You simply visit [Packagist](https://packagist.org) and hit the "Submit". This
+will prompt you to sign up if you haven't already, and then allows you to
+submit the URL to your VCS repository, at which point Packagist will start
+crawling it. Once it is done, your package will be available to anyone!
← [Basic usage](01-basic-usage.md) | [Command-line interface](03-cli.md) →
diff --git a/doc/03-cli.md b/doc/03-cli.md
index 2bb29001b..a8c1c1d40 100644
--- a/doc/03-cli.md
+++ b/doc/03-cli.md
@@ -87,7 +87,7 @@ resolution.
installing a package, you can use `--dry-run`. This will simulate the
installation and show you what would happen.
* **--dev:** Install packages listed in `require-dev` (this is the default behavior).
-* **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader
+* **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader
generation skips the `autoload-dev` rules.
* **--no-autoloader:** Skips autoloader generation.
* **--no-scripts:** Skips execution of scripts defined in `composer.json`.
@@ -97,6 +97,8 @@ resolution.
* **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to get a faster
autoloader. This is recommended especially for production, but can take
a bit of time to run so it is currently not done by default.
+* **--classmap-authoritative (-a):** Autoload classes from the classmap only.
+ Implicitly enables `--optimize-autoloader`.
## update
@@ -140,9 +142,11 @@ php composer.phar update vendor/*
* **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to get a faster
autoloader. This is recommended especially for production, but can take
a bit of time to run so it is currently not done by default.
+* **--classmap-authoritative (-a):** Autoload classes from the classmap only.
+ Implicitly enables `--optimize-autoloader`.
* **--lock:** Only updates the lock file hash to suppress warning about the
lock file being out of date.
-* **--with-dependencies** Add also all dependencies of whitelisted packages to the whitelist.
+* **--with-dependencies:** Add also all dependencies of whitelisted packages to the whitelist.
* **--prefer-stable:** Prefer stable versions of dependencies.
* **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal
versions of requirements, generally used with `--prefer-stable`.
@@ -177,9 +181,15 @@ php composer.phar require vendor/package:2.* vendor/package2:dev-master
* **--no-update:** Disables the automatic update of the dependencies.
* **--no-progress:** Removes the progress display that can mess with some
terminals or scripts which don't handle backspace characters.
-* **--update-no-dev** Run the dependency update with the --no-dev option.
-* **--update-with-dependencies** Also update dependencies of the newly
+* **--update-no-dev:** Run the dependency update with the `--no-dev` option.
+* **--update-with-dependencies:** Also update dependencies of the newly
required packages.
+* **--sort-packages:** Keep packages sorted in `composer.json`.
+* **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to
+ get a faster autoloader. This is recommended especially for production, but
+ can take a bit of time to run so it is currently not done by default.
+* **--classmap-authoritative (-a):** Autoload classes from the classmap only.
+ Implicitly enables `--optimize-autoloader`.
## remove
@@ -201,8 +211,13 @@ uninstalled.
* **--no-update:** Disables the automatic update of the dependencies.
* **--no-progress:** Removes the progress display that can mess with some
terminals or scripts which don't handle backspace characters.
-* **--update-no-dev** Run the dependency update with the --no-dev option.
-* **--update-with-dependencies** Also update dependencies of the removed packages.
+* **--update-no-dev:** Run the dependency update with the --no-dev option.
+* **--update-with-dependencies:** Also update dependencies of the removed packages.
+* **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to
+ get a faster autoloader. This is recommended especially for production, but
+ can take a bit of time to run so it is currently not done by default.
+* **--classmap-authoritative (-a):** Autoload classes from the classmap only.
+ Implicitly enables `--optimize-autoloader`.
## global
@@ -294,6 +309,18 @@ in your browser.
* **--homepage (-H):** Open the homepage instead of the repository URL.
+## suggests
+
+Lists all packages suggested by currently installed set of packages. You can
+optionally pass one or multiple package names in the format of `vendor/package`
+to limit output to suggestions made by those packages only.
+
+### Options
+
+* **--no-dev:** Excludes suggestions from `require-dev` packages.
+* **--verbose (-v):** Increased verbosity adds suggesting package name and
+ reason for suggestion.
+
## depends
The `depends` command tells you which other packages depend on a certain
@@ -327,7 +354,9 @@ php composer.phar validate
### Options
-* **--no-check-all:** Whether or not Composer does a complete validation.
+* **--no-check-all:** Do not emit a warning if requirements in `composer.json` use unbound version constraints.
+* **--no-check-lock:** Do not emit an error if `composer.lock` exists and is not up to date.
+* **--no-check-publish:** Do not emit an error if `composer.json` is unsuitable for publishing as a package on Packagist but is otherwise valid.
## status
@@ -375,7 +404,7 @@ sudo composer self-update
### Options
* **--rollback (-r):** Rollback to the last version you had installed.
-* **--clean-backups:** Delete old backups during an update. This makes the
+* **--clean-backups:** Delete old backups during an update. This makes the
current version of Composer the only backup available after the update.
## config
@@ -490,6 +519,8 @@ performance.
* **--optimize (-o):** Convert PSR-0/4 autoloading to classmap to get a faster
autoloader. This is recommended especially for production, but can take
a bit of time to run so it is currently not done by default.
+* **--classmap-authoritative (-a):** Autoload classes from the classmap only.
+ Implicitly enables `--optimize`.
* **--no-dev:** Disables autoload-dev rules.
## clear-cache
@@ -568,6 +599,8 @@ For example:
COMPOSER=composer-other.json php composer.phar install
```
+The generated lock file will use the same name: `composer-other.lock` in this example.
+
### COMPOSER_ROOT_VERSION
By setting this var you can specify the version of the root package, if it can
diff --git a/doc/05-repositories.md b/doc/05-repositories.md
index ffa29ede8..9308e1279 100644
--- a/doc/05-repositories.md
+++ b/doc/05-repositories.md
@@ -263,6 +263,10 @@ custom repository has priority over packagist. If you want to rename the
package, you should do so in the default (often master) branch and not in a
feature branch, since the package name is taken from the default branch.
+Also note that the override will not work if you change the `name` property
+in your forked repository's composer.json file as this needs to match the
+original for the override to work.
+
If other dependencies rely on the package you forked, it is possible to
inline-alias it so that it matches a constraint that it otherwise would not.
For more information [see the aliases article](articles/aliases.md).
@@ -602,6 +606,42 @@ imported. When an archive with a newer version is added in the artifact folder
and you run `update`, that version will be imported as well and Composer will
update to the latest version.
+### Path
+
+In addition to the artifact repository, you can use the path one, which allows
+you to depend on a relative directory. This can be especially useful when dealing
+with monolith repositories.
+
+For instance, if you have the following directory structure in your repository:
+```
+- apps
+\_ my-app
+ \_ composer.json
+- packages
+\_ my-package
+ \_ composer.json
+```
+
+Then, to add the package `my/package` as a dependency, in your `apps/my-app/composer.json`
+file, you can use the following configuration:
+
+```json
+{
+ "repositories": [
+ {
+ "type": "path",
+ "url": "../../packages/my-package"
+ }
+ ],
+ "require": {
+ "my/package": "*@dev"
+ }
+}
+```
+
+> **Note:** Repository paths can also contain wildcards like ``*`` and ``?``.
+> For details, see the [PHP glob function](http://php.net/glob).
+
## Disabling Packagist
You can disable the default Packagist repository by adding this to your
diff --git a/doc/06-config.md b/doc/06-config.md
index 0ee1d4fcb..b3e2909c6 100644
--- a/doc/06-config.md
+++ b/doc/06-config.md
@@ -46,6 +46,11 @@ A list of domain names and username/passwords to authenticate against them. For
example using `{"example.org": {"username": "alice", "password": "foo"}` as the
value of this option will let Composer authenticate against example.org.
+> **Note:** Authentication-related config options like `http-basic` and
+> `github-oauth` can also be specified inside a `auth.json` file that goes
+> besides your `composer.json`. That way you can gitignore it and every
+> developer can place their own credentials in there.
+
## platform
Lets you fake platform packages (PHP and extensions) so that you can emulate a
@@ -100,7 +105,7 @@ first until the cache fits.
## prepend-autoloader
-Defaults to `true`. If false, the Composer autoloader will not be prepended to
+Defaults to `true`. If `false`, the Composer autoloader will not be prepended to
existing autoloaders. This is sometimes required to fix interoperability issues
with other autoloaders.
@@ -111,13 +116,12 @@ autoloader. When null a random one will be generated.
## optimize-autoloader
-Defaults to `false`. Always optimize when dumping the autoloader.
+Defaults to `false`. If `true`, always optimize when dumping the autoloader.
## classmap-authoritative
-Defaults to `false`. If `true`, the Composer autoloader will not scan the
-filesystem for classes that are not found in the class map. Implies
-'optimize-autoloader'.
+Defaults to `false`. If `true`, the Composer autoloader will only load classes
+from the classmap. Implies `optimize-autoloader`.
## github-domains
@@ -126,7 +130,7 @@ used for GitHub Enterprise setups.
## github-expose-hostname
-Defaults to `true`. If set to `false`, the OAuth tokens created to access the
+Defaults to `true`. If `false`, the OAuth tokens created to access the
github API will have a date instead of the machine hostname.
## notify-on-install
@@ -164,9 +168,4 @@ Example:
}
```
-> **Note:** Authentication-related config options like `http-basic` and
-> `github-oauth` can also be specified inside a `auth.json` file that goes
-> besides your `composer.json`. That way you can gitignore it and every
-> developer can place their own credentials in there.
-
← [Repositories](05-repositories.md) | [Community](07-community.md) →
diff --git a/doc/articles/handling-private-packages-with-satis.md b/doc/articles/handling-private-packages-with-satis.md
index e7ce665b6..4294de4fb 100644
--- a/doc/articles/handling-private-packages-with-satis.md
+++ b/doc/articles/handling-private-packages-with-satis.md
@@ -73,7 +73,7 @@ constraint if you want really specific versions.
```
Once you've done this, you just run `php bin/satis build `.
-For example `php bin/satis build config.json web/` would read the `config.json`
+For example `php bin/satis build satis.json web/` would read the `satis.json`
file and build a static repository inside the `web/` directory.
When you ironed out that process, what you would typically do is run this
diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md
index dec1fa06d..14e5b5a63 100644
--- a/doc/articles/scripts.md
+++ b/doc/articles/scripts.md
@@ -23,34 +23,34 @@ Composer fires the following named events during its execution process:
### Command Events
- **pre-install-cmd**: occurs before the `install` command is executed.
-- **post-install-cmd**: occurs after the `install` command is executed.
+- **post-install-cmd**: occurs after the `install` command has been executed.
- **pre-update-cmd**: occurs before the `update` command is executed.
-- **post-update-cmd**: occurs after the `update` command is executed.
+- **post-update-cmd**: occurs after the `update` command has been executed.
- **pre-status-cmd**: occurs before the `status` command is executed.
-- **post-status-cmd**: occurs after the `status` command is executed.
+- **post-status-cmd**: occurs after the `status` command has been executed.
- **pre-archive-cmd**: occurs before the `archive` command is executed.
-- **post-archive-cmd**: occurs after the `archive` command is executed.
+- **post-archive-cmd**: occurs after the `archive` command has been executed.
- **pre-autoload-dump**: occurs before the autoloader is dumped, either
during `install`/`update`, or via the `dump-autoload` command.
-- **post-autoload-dump**: occurs after the autoloader is dumped, either
+- **post-autoload-dump**: occurs after the autoloader has been dumped, either
during `install`/`update`, or via the `dump-autoload` command.
- **post-root-package-install**: occurs after the root package has been
installed, during the `create-project` command.
-- **post-create-project-cmd**: occurs after the `create-project` command is
- executed.
+- **post-create-project-cmd**: occurs after the `create-project` command has
+ been executed.
### Installer Events
- **pre-dependencies-solving**: occurs before the dependencies are resolved.
-- **post-dependencies-solving**: occurs after the dependencies are resolved.
+- **post-dependencies-solving**: occurs after the dependencies have been resolved.
### Package Events
- **pre-package-install**: occurs before a package is installed.
-- **post-package-install**: occurs after a package is installed.
+- **post-package-install**: occurs after a package has been installed.
- **pre-package-update**: occurs before a package is updated.
-- **post-package-update**: occurs after a package is updated.
-- **pre-package-uninstall**: occurs before a package has been uninstalled.
+- **post-package-update**: occurs after a package has been updated.
+- **pre-package-uninstall**: occurs before a package is uninstalled.
- **post-package-uninstall**: occurs after a package has been uninstalled.
### Plugin Events
@@ -82,6 +82,10 @@ For any given event:
and command-line executable commands.
- PHP classes containing defined callbacks must be autoloadable via Composer's
autoload functionality.
+- Callbacks can only autoload classes from psr-0, psr-4 and classmap
+definitions. If a defined callback relies on functions defined outside of a
+class, the callback itself is responsible for loading the file containing these
+functions.
Script definition example:
@@ -96,7 +100,10 @@ Script definition example:
"MyVendor\\MyClass::warmCache",
"phpunit -c app/"
],
- "post-create-project-cmd" : [
+ "post-autoload-dump": [
+ "MyVendor\\MyClass::postAutoloadDump"
+ ],
+ "post-create-project-cmd": [
"php -r \"copy('config/local-example.php', 'config/local.php');\""
]
}
@@ -122,6 +129,14 @@ class MyClass
// do stuff
}
+ public static function postAutoloadDump(Event $event)
+ {
+ $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
+ require $vendorDir . '/autoload.php';
+
+ some_function_from_an_autoloaded_file();
+ }
+
public static function postPackageInstall(PackageEvent $event)
{
$installedPackage = $event->getOperation()->getPackage();
diff --git a/doc/articles/troubleshooting.md b/doc/articles/troubleshooting.md
index 25279bddb..a6f082ab7 100644
--- a/doc/articles/troubleshooting.md
+++ b/doc/articles/troubleshooting.md
@@ -43,6 +43,10 @@ This is a list of common pitfalls on using Composer, and how to avoid them.
5. If you are updating to a recently published version of a package, be aware that
Packagist has a delay of up to 1 minute before new packages are visible to Composer.
+6. If you are updating a single package, it may depend on newer versions itself.
+ In this case add the `--with-dependencies` argument **or** add all dependencies which
+ need an update to the command.
+
## Package not found on travis-ci.org
1. Check the ["Package not found"](#package-not-found) item above.
@@ -61,13 +65,13 @@ This is a list of common pitfalls on using Composer, and how to avoid them.
## Package not found in a Jenkins-build
1. Check the ["Package not found"](#package-not-found) item above.
-2. Reason for failing is similar to the problem which can occur on travis-ci.org: The
- git-clone / checkout within Jenkins leaves the branch in a "detached HEAD"-state. As
- a result, Composer is not able to identify the version of the current checked out branch
- and may not be able to resolve a cyclic dependency. To solve this problem, you can use
- the "Additional Behaviours" -> "Check out to specific local branch" in your Git-settings
- for your Jenkins-job, where your "local branch" shall be the same branch as you are
- checking out. Using this, the checkout will not be in detached state any more and cyclic
+2. Reason for failing is similar to the problem which can occur on travis-ci.org: The
+ git-clone / checkout within Jenkins leaves the branch in a "detached HEAD"-state. As
+ a result, Composer is not able to identify the version of the current checked out branch
+ and may not be able to resolve a cyclic dependency. To solve this problem, you can use
+ the "Additional Behaviours" -> "Check out to specific local branch" in your Git-settings
+ for your Jenkins-job, where your "local branch" shall be the same branch as you are
+ checking out. Using this, the checkout will not be in detached state any more and cyclic
dependency is recognized correctly.
## Need to override a package version
@@ -168,3 +172,28 @@ To enable the swap you can use for example:
/sbin/mkswap /var/swap.1
/sbin/swapon /var/swap.1
```
+
+## Degraded Mode
+
+Due to some intermittent issues on Travis and other systems, we introduced a
+degraded network mode which helps Composer finish successfully but disables
+a few optimizations. This is enabled automatically when an issue is first
+detected. If you see this issue sporadically you probably don't have to worry
+(a slow or overloaded network can also cause those time outs), but if it
+appears repeatedly you might want to look at the options below to identify
+and resolve it.
+
+If you have been pointed to this page, you want to check a few things:
+
+- If you are using ESET antivirus, go in "Advanced Settings" and disable "HTTP-scanner"
+ under "web access protection"
+- If you are using IPv6, try disabling it. If that solves your issues, get in touch
+ with your ISP or server host, the problem is not at the Packagist level but in the
+ routing rules between you and Packagist (i.e. the internet at large). The best way to get
+ these fixed is raise awareness to the network engineers that have the power to fix it.
+
+ To disable IPv6 on Linux, try using this command which appends a
+ rule preferring IPv4 over IPv6 to your config:
+
+ `sudo sh -c "echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf"`
+- If none of the above helped, please report the error.
diff --git a/doc/articles/versions.md b/doc/articles/versions.md
new file mode 100644
index 000000000..226fd84e6
--- /dev/null
+++ b/doc/articles/versions.md
@@ -0,0 +1,118 @@
+
+
+# Versions
+
+## Basic Constraints
+
+### Exact
+
+You can specify the exact version of a package. This will tell Composer to
+install this version and this version only. If other dependencies require
+a different version, the solver will ultimately fail and abort any install
+or update procedures.
+
+Example: `1.0.2`
+
+### Range
+
+By using comparison operators you can specify ranges of valid versions. Valid
+operators are `>`, `>=`, `<`, `<=`, `!=`.
+
+You can define multiple ranges. Ranges separated by a space (
)
+or comma (`,`) will be treated as a **logical AND**. A double pipe (`||`)
+will be treated as a **logical OR**. AND has higher precedence than OR.
+
+> **Note:** Be careful when using unbounded ranges as you might end up
+> unexpectedly installing versions that break backwards compatibility.
+> Consider using the [caret](#caret) operator instead for safety.
+
+Examples:
+
+* `>=1.0`
+* `>=1.0 <2.0`
+* `>=1.0 <1.1 || >=1.2`
+
+### Range (Hyphen)
+
+Inclusive set of versions. Partial versions on the right include are completed
+with a wildcard. For example `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` as the
+`2.0` becomes `2.0.*`. On the other hand `1.0.0 - 2.1.0` is equivalent to
+`>=1.0.0 <=2.1.0`.
+
+Example: `1.0 - 2.0`
+
+### Wildcard
+
+You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of
+`>=1.0 <1.1`.
+
+Example: `1.0.*`
+
+## Next Significant Release Operators
+
+### Tilde
+
+The `~` operator is best explained by example: `~1.2` is equivalent to
+`>=1.2 <2.0.0`, while `~1.2.3` is equivalent to `>=1.2.3 <1.3.0`. As you can see
+it is mostly useful for projects respecting [semantic
+versioning](http://semver.org/). A common usage would be to mark the minimum
+minor version you depend on, like `~1.2` (which allows anything up to, but not
+including, 2.0). Since in theory there should be no backwards compatibility
+breaks until 2.0, that works well. Another way of looking at it is that using
+`~` specifies a minimum version, but allows the last digit specified to go up.
+
+Example: `~1.2`
+
+> **Note:** Though `2.0-beta.1` is strictly before `2.0`, a version constraint
+> like `~1.2` would not install it. As said above `~1.2` only means the `.2`
+> can change but the `1.` part is fixed.
+
+> **Note:** The `~` operator has an exception on its behavior for the major
+> release number. This means for example that `~1` is the same as `~1.0` as
+> it will not allow the major number to increase trying to keep backwards
+> compatibility.
+
+### Caret
+
+The `^` operator behaves very similarly but it sticks closer to semantic
+versioning, and will always allow non-breaking updates. For example `^1.2.3`
+is equivalent to `>=1.2.3 <2.0.0` as none of the releases until 2.0 should
+break backwards compatibility. For pre-1.0 versions it also acts with safety
+in mind and treats `^0.3` as `>=0.3.0 <0.4.0`.
+
+This is the recommended operator for maximum interoperability when writing
+library code.
+
+Example: `^1.2.3`
+
+## Stability
+
+If you are using a constraint that does not explicitly define a stability,
+Composer will default internally to `-dev` or `-stable`, depending on the
+operator(s) used. This happens transparently.
+
+If you wish to explicitly consider only the stable release in the comparison,
+add the suffix `-stable`.
+
+Examples:
+
+ Constraint | Internally
+------------------- | ------------------------
+ `1.2.3` | `=1.2.3.0-stable`
+ `>1.2` | `>1.2.0.0-stable`
+ `>=1.2` | `>=1.2.0.0-dev`
+ `>=1.2-stable` | `>=1.2.0.0-stable`
+ `<1.3` | `<1.3.0.0-dev`
+ `<=1.3` | `<=1.3.0.0-stable`
+ `1 - 2` | `>=1.0.0.0-dev <3.0.0.0-dev`
+ `~1.3` | `>=1.3.0.0-dev <2.0.0.0-dev`
+ `1.4.*` | `>=1.4.0.0-dev <1.5.0.0-dev`
+
+## Test version constraints
+
+You can test version constraints using [semver.mwl.be](http://semver.mwl.be).
+Fill in a package name and it will autofill the default version constraint
+which Composer would add to your `composer.json` file. You can adjust the
+version constraint and the tool will highlight all releases that match.
diff --git a/res/spdx-licenses.json b/res/spdx-licenses.json
deleted file mode 100644
index 3e1d93c35..000000000
--- a/res/spdx-licenses.json
+++ /dev/null
@@ -1,1226 +0,0 @@
-{
- "Glide": [
- "3dfx Glide License",
- false
- ],
- "Abstyles": [
- "Abstyles License",
- false
- ],
- "AFL-1.1": [
- "Academic Free License v1.1",
- true
- ],
- "AFL-1.2": [
- "Academic Free License v1.2",
- true
- ],
- "AFL-2.0": [
- "Academic Free License v2.0",
- true
- ],
- "AFL-2.1": [
- "Academic Free License v2.1",
- true
- ],
- "AFL-3.0": [
- "Academic Free License v3.0",
- true
- ],
- "AMPAS": [
- "Academy of Motion Picture Arts and Sciences BSD",
- false
- ],
- "APL-1.0": [
- "Adaptive Public License 1.0",
- true
- ],
- "Adobe-Glyph": [
- "Adobe Glyph List License",
- false
- ],
- "APAFML": [
- "Adobe Postscript AFM License",
- false
- ],
- "Adobe-2006": [
- "Adobe Systems Incorporated Source Code License Agreement",
- false
- ],
- "AGPL-1.0": [
- "Affero General Public License v1.0",
- false
- ],
- "Afmparse": [
- "Afmparse License",
- false
- ],
- "Aladdin": [
- "Aladdin Free Public License",
- false
- ],
- "ADSL": [
- "Amazon Digital Services License",
- false
- ],
- "AMDPLPA": [
- "AMD's plpa_map.c License",
- false
- ],
- "ANTLR-PD": [
- "ANTLR Software Rights Notice",
- false
- ],
- "Apache-1.0": [
- "Apache License 1.0",
- false
- ],
- "Apache-1.1": [
- "Apache License 1.1",
- true
- ],
- "Apache-2.0": [
- "Apache License 2.0",
- true
- ],
- "AML": [
- "Apple MIT License",
- false
- ],
- "APSL-1.0": [
- "Apple Public Source License 1.0",
- true
- ],
- "APSL-1.1": [
- "Apple Public Source License 1.1",
- true
- ],
- "APSL-1.2": [
- "Apple Public Source License 1.2",
- true
- ],
- "APSL-2.0": [
- "Apple Public Source License 2.0",
- true
- ],
- "Artistic-1.0": [
- "Artistic License 1.0",
- true
- ],
- "Artistic-1.0-Perl": [
- "Artistic License 1.0 (Perl)",
- true
- ],
- "Artistic-1.0-cl8": [
- "Artistic License 1.0 w/clause 8",
- true
- ],
- "Artistic-2.0": [
- "Artistic License 2.0",
- true
- ],
- "AAL": [
- "Attribution Assurance License",
- true
- ],
- "Bahyph": [
- "Bahyph License",
- false
- ],
- "Barr": [
- "Barr License",
- false
- ],
- "Beerware": [
- "Beerware License",
- false
- ],
- "BitTorrent-1.0": [
- "BitTorrent Open Source License v1.0",
- false
- ],
- "BitTorrent-1.1": [
- "BitTorrent Open Source License v1.1",
- false
- ],
- "BSL-1.0": [
- "Boost Software License 1.0",
- true
- ],
- "Borceux": [
- "Borceux license",
- false
- ],
- "BSD-2-Clause": [
- "BSD 2-clause \"Simplified\" License",
- true
- ],
- "BSD-2-Clause-FreeBSD": [
- "BSD 2-clause FreeBSD License",
- false
- ],
- "BSD-2-Clause-NetBSD": [
- "BSD 2-clause NetBSD License",
- false
- ],
- "BSD-3-Clause": [
- "BSD 3-clause \"New\" or \"Revised\" License",
- true
- ],
- "BSD-3-Clause-Clear": [
- "BSD 3-clause Clear License",
- false
- ],
- "BSD-4-Clause": [
- "BSD 4-clause \"Original\" or \"Old\" License",
- false
- ],
- "BSD-Protection": [
- "BSD Protection License",
- false
- ],
- "BSD-3-Clause-Attribution": [
- "BSD with attribution",
- false
- ],
- "BSD-4-Clause-UC": [
- "BSD-4-Clause (University of California-Specific)",
- false
- ],
- "bzip2-1.0.5": [
- "bzip2 and libbzip2 License v1.0.5",
- false
- ],
- "bzip2-1.0.6": [
- "bzip2 and libbzip2 License v1.0.6",
- false
- ],
- "Caldera": [
- "Caldera License",
- false
- ],
- "CECILL-1.0": [
- "CeCILL Free Software License Agreement v1.0",
- false
- ],
- "CECILL-1.1": [
- "CeCILL Free Software License Agreement v1.1",
- false
- ],
- "CECILL-2.0": [
- "CeCILL Free Software License Agreement v2.0",
- false
- ],
- "CECILL-B": [
- "CeCILL-B Free Software License Agreement",
- false
- ],
- "CECILL-C": [
- "CeCILL-C Free Software License Agreement",
- false
- ],
- "ClArtistic": [
- "Clarified Artistic License",
- false
- ],
- "MIT-CMU": [
- "CMU License",
- false
- ],
- "CNRI-Python": [
- "CNRI Python License",
- true
- ],
- "CNRI-Python-GPL-Compatible": [
- "CNRI Python Open Source GPL Compatible License Agreement",
- false
- ],
- "CPOL-1.02": [
- "Code Project Open License 1.02",
- false
- ],
- "CDDL-1.0": [
- "Common Development and Distribution License 1.0",
- true
- ],
- "CDDL-1.1": [
- "Common Development and Distribution License 1.1",
- false
- ],
- "CPAL-1.0": [
- "Common Public Attribution License 1.0",
- true
- ],
- "CPL-1.0": [
- "Common Public License 1.0",
- true
- ],
- "CATOSL-1.1": [
- "Computer Associates Trusted Open Source License 1.1",
- true
- ],
- "Condor-1.1": [
- "Condor Public License v1.1",
- false
- ],
- "CC-BY-1.0": [
- "Creative Commons Attribution 1.0",
- false
- ],
- "CC-BY-2.0": [
- "Creative Commons Attribution 2.0",
- false
- ],
- "CC-BY-2.5": [
- "Creative Commons Attribution 2.5",
- false
- ],
- "CC-BY-3.0": [
- "Creative Commons Attribution 3.0",
- false
- ],
- "CC-BY-4.0": [
- "Creative Commons Attribution 4.0",
- false
- ],
- "CC-BY-ND-1.0": [
- "Creative Commons Attribution No Derivatives 1.0",
- false
- ],
- "CC-BY-ND-2.0": [
- "Creative Commons Attribution No Derivatives 2.0",
- false
- ],
- "CC-BY-ND-2.5": [
- "Creative Commons Attribution No Derivatives 2.5",
- false
- ],
- "CC-BY-ND-3.0": [
- "Creative Commons Attribution No Derivatives 3.0",
- false
- ],
- "CC-BY-ND-4.0": [
- "Creative Commons Attribution No Derivatives 4.0",
- false
- ],
- "CC-BY-NC-1.0": [
- "Creative Commons Attribution Non Commercial 1.0",
- false
- ],
- "CC-BY-NC-2.0": [
- "Creative Commons Attribution Non Commercial 2.0",
- false
- ],
- "CC-BY-NC-2.5": [
- "Creative Commons Attribution Non Commercial 2.5",
- false
- ],
- "CC-BY-NC-3.0": [
- "Creative Commons Attribution Non Commercial 3.0",
- false
- ],
- "CC-BY-NC-4.0": [
- "Creative Commons Attribution Non Commercial 4.0",
- false
- ],
- "CC-BY-NC-ND-1.0": [
- "Creative Commons Attribution Non Commercial No Derivatives 1.0",
- false
- ],
- "CC-BY-NC-ND-2.0": [
- "Creative Commons Attribution Non Commercial No Derivatives 2.0",
- false
- ],
- "CC-BY-NC-ND-2.5": [
- "Creative Commons Attribution Non Commercial No Derivatives 2.5",
- false
- ],
- "CC-BY-NC-ND-3.0": [
- "Creative Commons Attribution Non Commercial No Derivatives 3.0",
- false
- ],
- "CC-BY-NC-ND-4.0": [
- "Creative Commons Attribution Non Commercial No Derivatives 4.0",
- false
- ],
- "CC-BY-NC-SA-1.0": [
- "Creative Commons Attribution Non Commercial Share Alike 1.0",
- false
- ],
- "CC-BY-NC-SA-2.0": [
- "Creative Commons Attribution Non Commercial Share Alike 2.0",
- false
- ],
- "CC-BY-NC-SA-2.5": [
- "Creative Commons Attribution Non Commercial Share Alike 2.5",
- false
- ],
- "CC-BY-NC-SA-3.0": [
- "Creative Commons Attribution Non Commercial Share Alike 3.0",
- false
- ],
- "CC-BY-NC-SA-4.0": [
- "Creative Commons Attribution Non Commercial Share Alike 4.0",
- false
- ],
- "CC-BY-SA-1.0": [
- "Creative Commons Attribution Share Alike 1.0",
- false
- ],
- "CC-BY-SA-2.0": [
- "Creative Commons Attribution Share Alike 2.0",
- false
- ],
- "CC-BY-SA-2.5": [
- "Creative Commons Attribution Share Alike 2.5",
- false
- ],
- "CC-BY-SA-3.0": [
- "Creative Commons Attribution Share Alike 3.0",
- false
- ],
- "CC-BY-SA-4.0": [
- "Creative Commons Attribution Share Alike 4.0",
- false
- ],
- "CC0-1.0": [
- "Creative Commons Zero v1.0 Universal",
- false
- ],
- "Crossword": [
- "Crossword License",
- false
- ],
- "CUA-OPL-1.0": [
- "CUA Office Public License v1.0",
- true
- ],
- "Cube": [
- "Cube License",
- false
- ],
- "D-FSL-1.0": [
- "Deutsche Freie Software Lizenz",
- false
- ],
- "diffmark": [
- "diffmark license",
- false
- ],
- "WTFPL": [
- "Do What The F*ck You Want To Public License",
- false
- ],
- "DOC": [
- "DOC License",
- false
- ],
- "Dotseqn": [
- "Dotseqn License",
- false
- ],
- "DSDP": [
- "DSDP License",
- false
- ],
- "dvipdfm": [
- "dvipdfm License",
- false
- ],
- "EPL-1.0": [
- "Eclipse Public License 1.0",
- true
- ],
- "eCos-2.0": [
- "eCos license version 2.0",
- false
- ],
- "ECL-1.0": [
- "Educational Community License v1.0",
- true
- ],
- "ECL-2.0": [
- "Educational Community License v2.0",
- true
- ],
- "eGenix": [
- "eGenix.com Public License 1.1.0",
- false
- ],
- "EFL-1.0": [
- "Eiffel Forum License v1.0",
- true
- ],
- "EFL-2.0": [
- "Eiffel Forum License v2.0",
- true
- ],
- "MIT-advertising": [
- "Enlightenment License (e16)",
- false
- ],
- "MIT-enna": [
- "enna License",
- false
- ],
- "Entessa": [
- "Entessa Public License v1.0",
- true
- ],
- "ErlPL-1.1": [
- "Erlang Public License v1.1",
- false
- ],
- "EUDatagrid": [
- "EU DataGrid Software License",
- true
- ],
- "EUPL-1.0": [
- "European Union Public License 1.0",
- false
- ],
- "EUPL-1.1": [
- "European Union Public License 1.1",
- true
- ],
- "Eurosym": [
- "Eurosym License",
- false
- ],
- "Fair": [
- "Fair License",
- true
- ],
- "MIT-feh": [
- "feh License",
- false
- ],
- "Frameworx-1.0": [
- "Frameworx Open License 1.0",
- true
- ],
- "FTL": [
- "Freetype Project License",
- false
- ],
- "FSFUL": [
- "FSF Unlimited License",
- false
- ],
- "FSFULLR": [
- "FSF Unlimited License (with License Retention)",
- false
- ],
- "Giftware": [
- "Giftware License",
- false
- ],
- "GL2PS": [
- "GL2PS License",
- false
- ],
- "Glulxe": [
- "Glulxe License",
- false
- ],
- "AGPL-3.0": [
- "GNU Affero General Public License v3.0",
- true
- ],
- "GFDL-1.1": [
- "GNU Free Documentation License v1.1",
- false
- ],
- "GFDL-1.2": [
- "GNU Free Documentation License v1.2",
- false
- ],
- "GFDL-1.3": [
- "GNU Free Documentation License v1.3",
- false
- ],
- "GPL-1.0": [
- "GNU General Public License v1.0 only",
- false
- ],
- "GPL-1.0+": [
- "GNU General Public License v1.0 or later",
- false
- ],
- "GPL-2.0": [
- "GNU General Public License v2.0 only",
- true
- ],
- "GPL-2.0+": [
- "GNU General Public License v2.0 or later",
- true
- ],
- "GPL-2.0-with-autoconf-exception": [
- "GNU General Public License v2.0 w/Autoconf exception",
- true
- ],
- "GPL-2.0-with-bison-exception": [
- "GNU General Public License v2.0 w/Bison exception",
- true
- ],
- "GPL-2.0-with-classpath-exception": [
- "GNU General Public License v2.0 w/Classpath exception",
- true
- ],
- "GPL-2.0-with-font-exception": [
- "GNU General Public License v2.0 w/Font exception",
- true
- ],
- "GPL-2.0-with-GCC-exception": [
- "GNU General Public License v2.0 w/GCC Runtime Library exception",
- true
- ],
- "GPL-3.0": [
- "GNU General Public License v3.0 only",
- true
- ],
- "GPL-3.0+": [
- "GNU General Public License v3.0 or later",
- true
- ],
- "GPL-3.0-with-autoconf-exception": [
- "GNU General Public License v3.0 w/Autoconf exception",
- true
- ],
- "GPL-3.0-with-GCC-exception": [
- "GNU General Public License v3.0 w/GCC Runtime Library exception",
- true
- ],
- "LGPL-2.1": [
- "GNU Lesser General Public License v2.1 only",
- true
- ],
- "LGPL-2.1+": [
- "GNU Lesser General Public License v2.1 or later",
- true
- ],
- "LGPL-3.0": [
- "GNU Lesser General Public License v3.0 only",
- true
- ],
- "LGPL-3.0+": [
- "GNU Lesser General Public License v3.0 or later",
- true
- ],
- "LGPL-2.0": [
- "GNU Library General Public License v2 only",
- true
- ],
- "LGPL-2.0+": [
- "GNU Library General Public License v2 or later",
- true
- ],
- "gnuplot": [
- "gnuplot License",
- false
- ],
- "gSOAP-1.3b": [
- "gSOAP Public License v1.3b",
- false
- ],
- "HaskellReport": [
- "Haskell Language Report License",
- false
- ],
- "HPND": [
- "Historic Permission Notice and Disclaimer",
- true
- ],
- "IBM-pibs": [
- "IBM PowerPC Initialization and Boot Software",
- false
- ],
- "IPL-1.0": [
- "IBM Public License v1.0",
- true
- ],
- "ImageMagick": [
- "ImageMagick License",
- false
- ],
- "iMatix": [
- "iMatix Standard Function Library Agreement",
- false
- ],
- "Imlib2": [
- "Imlib2 License",
- false
- ],
- "IJG": [
- "Independent JPEG Group License",
- false
- ],
- "Intel-ACPI": [
- "Intel ACPI Software License Agreement",
- false
- ],
- "Intel": [
- "Intel Open Source License",
- true
- ],
- "IPA": [
- "IPA Font License",
- true
- ],
- "ISC": [
- "ISC License",
- true
- ],
- "JasPer-2.0": [
- "JasPer License",
- false
- ],
- "JSON": [
- "JSON License",
- false
- ],
- "LPPL-1.3a": [
- "LaTeX Project Public License 1.3a",
- false
- ],
- "LPPL-1.0": [
- "LaTeX Project Public License v1.0",
- false
- ],
- "LPPL-1.1": [
- "LaTeX Project Public License v1.1",
- false
- ],
- "LPPL-1.2": [
- "LaTeX Project Public License v1.2",
- false
- ],
- "LPPL-1.3c": [
- "LaTeX Project Public License v1.3c",
- true
- ],
- "Latex2e": [
- "Latex2e License",
- false
- ],
- "BSD-3-Clause-LBNL": [
- "Lawrence Berkeley National Labs BSD variant license",
- false
- ],
- "Leptonica": [
- "Leptonica License",
- false
- ],
- "Libpng": [
- "libpng License",
- false
- ],
- "libtiff": [
- "libtiff License",
- false
- ],
- "LPL-1.02": [
- "Lucent Public License v1.02",
- true
- ],
- "LPL-1.0": [
- "Lucent Public License Version 1.0",
- true
- ],
- "MakeIndex": [
- "MakeIndex License",
- false
- ],
- "MTLL": [
- "Matrix Template Library License",
- false
- ],
- "MS-PL": [
- "Microsoft Public License",
- true
- ],
- "MS-RL": [
- "Microsoft Reciprocal License",
- true
- ],
- "MirOS": [
- "MirOS Licence",
- true
- ],
- "MITNFA": [
- "MIT +no-false-attribs license",
- false
- ],
- "MIT": [
- "MIT License",
- true
- ],
- "Motosoto": [
- "Motosoto License",
- true
- ],
- "MPL-1.0": [
- "Mozilla Public License 1.0",
- true
- ],
- "MPL-1.1": [
- "Mozilla Public License 1.1",
- true
- ],
- "MPL-2.0": [
- "Mozilla Public License 2.0",
- true
- ],
- "MPL-2.0-no-copyleft-exception": [
- "Mozilla Public License 2.0 (no copyleft exception)",
- true
- ],
- "mpich2": [
- "mpich2 License",
- false
- ],
- "Multics": [
- "Multics License",
- true
- ],
- "Mup": [
- "Mup License",
- false
- ],
- "NASA-1.3": [
- "NASA Open Source Agreement 1.3",
- true
- ],
- "Naumen": [
- "Naumen Public License",
- true
- ],
- "NBPL-1.0": [
- "Net Boolean Public License v1",
- false
- ],
- "NetCDF": [
- "NetCDF license",
- false
- ],
- "NGPL": [
- "Nethack General Public License",
- true
- ],
- "NOSL": [
- "Netizen Open Source License",
- false
- ],
- "NPL-1.0": [
- "Netscape Public License v1.0",
- false
- ],
- "NPL-1.1": [
- "Netscape Public License v1.1",
- false
- ],
- "Newsletr": [
- "Newsletr License",
- false
- ],
- "NLPL": [
- "No Limit Public License",
- false
- ],
- "Nokia": [
- "Nokia Open Source License",
- true
- ],
- "NPOSL-3.0": [
- "Non-Profit Open Software License 3.0",
- true
- ],
- "Noweb": [
- "Noweb License",
- false
- ],
- "NRL": [
- "NRL License",
- false
- ],
- "NTP": [
- "NTP License",
- true
- ],
- "Nunit": [
- "Nunit License",
- false
- ],
- "OCLC-2.0": [
- "OCLC Research Public License 2.0",
- true
- ],
- "ODbL-1.0": [
- "ODC Open Database License v1.0",
- false
- ],
- "PDDL-1.0": [
- "ODC Public Domain Dedication & License 1.0",
- false
- ],
- "OGTSL": [
- "Open Group Test Suite License",
- true
- ],
- "OLDAP-2.2.2": [
- "Open LDAP Public License 2.2.2",
- false
- ],
- "OLDAP-1.1": [
- "Open LDAP Public License v1.1",
- false
- ],
- "OLDAP-1.2": [
- "Open LDAP Public License v1.2",
- false
- ],
- "OLDAP-1.3": [
- "Open LDAP Public License v1.3",
- false
- ],
- "OLDAP-1.4": [
- "Open LDAP Public License v1.4",
- false
- ],
- "OLDAP-2.0": [
- "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)",
- false
- ],
- "OLDAP-2.0.1": [
- "Open LDAP Public License v2.0.1",
- false
- ],
- "OLDAP-2.1": [
- "Open LDAP Public License v2.1",
- false
- ],
- "OLDAP-2.2": [
- "Open LDAP Public License v2.2",
- false
- ],
- "OLDAP-2.2.1": [
- "Open LDAP Public License v2.2.1",
- false
- ],
- "OLDAP-2.3": [
- "Open LDAP Public License v2.3",
- false
- ],
- "OLDAP-2.4": [
- "Open LDAP Public License v2.4",
- false
- ],
- "OLDAP-2.5": [
- "Open LDAP Public License v2.5",
- false
- ],
- "OLDAP-2.6": [
- "Open LDAP Public License v2.6",
- false
- ],
- "OLDAP-2.7": [
- "Open LDAP Public License v2.7",
- false
- ],
- "OML": [
- "Open Market License",
- false
- ],
- "OPL-1.0": [
- "Open Public License v1.0",
- false
- ],
- "OSL-1.0": [
- "Open Software License 1.0",
- true
- ],
- "OSL-1.1": [
- "Open Software License 1.1",
- false
- ],
- "OSL-2.0": [
- "Open Software License 2.0",
- true
- ],
- "OSL-2.1": [
- "Open Software License 2.1",
- true
- ],
- "OSL-3.0": [
- "Open Software License 3.0",
- true
- ],
- "OLDAP-2.8": [
- "OpenLDAP Public License v2.8",
- false
- ],
- "OpenSSL": [
- "OpenSSL License",
- false
- ],
- "PHP-3.0": [
- "PHP License v3.0",
- true
- ],
- "PHP-3.01": [
- "PHP License v3.01",
- false
- ],
- "Plexus": [
- "Plexus Classworlds License",
- false
- ],
- "PostgreSQL": [
- "PostgreSQL License",
- true
- ],
- "psfrag": [
- "psfrag License",
- false
- ],
- "psutils": [
- "psutils License",
- false
- ],
- "Python-2.0": [
- "Python License 2.0",
- true
- ],
- "QPL-1.0": [
- "Q Public License 1.0",
- true
- ],
- "Qhull": [
- "Qhull License",
- false
- ],
- "Rdisc": [
- "Rdisc License",
- false
- ],
- "RPSL-1.0": [
- "RealNetworks Public Source License v1.0",
- true
- ],
- "RPL-1.1": [
- "Reciprocal Public License 1.1",
- true
- ],
- "RPL-1.5": [
- "Reciprocal Public License 1.5",
- true
- ],
- "RHeCos-1.1": [
- "Red Hat eCos Public License v1.1",
- false
- ],
- "RSCPL": [
- "Ricoh Source Code Public License",
- true
- ],
- "Ruby": [
- "Ruby License",
- false
- ],
- "SAX-PD": [
- "Sax Public Domain Notice",
- false
- ],
- "Saxpath": [
- "Saxpath License",
- false
- ],
- "SCEA": [
- "SCEA Shared Source License",
- false
- ],
- "SWL": [
- "Scheme Widget Library (SWL) Software License Agreement",
- false
- ],
- "SGI-B-1.0": [
- "SGI Free Software License B v1.0",
- false
- ],
- "SGI-B-1.1": [
- "SGI Free Software License B v1.1",
- false
- ],
- "SGI-B-2.0": [
- "SGI Free Software License B v2.0",
- false
- ],
- "OFL-1.0": [
- "SIL Open Font License 1.0",
- false
- ],
- "OFL-1.1": [
- "SIL Open Font License 1.1",
- true
- ],
- "SimPL-2.0": [
- "Simple Public License 2.0",
- true
- ],
- "Sleepycat": [
- "Sleepycat License",
- true
- ],
- "SNIA": [
- "SNIA Public License 1.1",
- false
- ],
- "SMLNJ": [
- "Standard ML of New Jersey License",
- false
- ],
- "StandardML-NJ": [
- "Standard ML of New Jersey License",
- false
- ],
- "SugarCRM-1.1.3": [
- "SugarCRM Public License v1.1.3",
- false
- ],
- "SISSL": [
- "Sun Industry Standards Source License v1.1",
- true
- ],
- "SISSL-1.2": [
- "Sun Industry Standards Source License v1.2",
- false
- ],
- "SPL-1.0": [
- "Sun Public License v1.0",
- true
- ],
- "Watcom-1.0": [
- "Sybase Open Watcom Public License 1.0",
- true
- ],
- "TCL": [
- "TCL/TK License",
- false
- ],
- "Unlicense": [
- "The Unlicense",
- false
- ],
- "TMate": [
- "TMate Open Source License",
- false
- ],
- "TORQUE-1.1": [
- "TORQUE v2.5+ Software License v1.1",
- false
- ],
- "TOSL": [
- "Trusster Open Source License",
- false
- ],
- "Unicode-TOU": [
- "Unicode Terms of Use",
- false
- ],
- "NCSA": [
- "University of Illinois/NCSA Open Source License",
- true
- ],
- "Vim": [
- "Vim License",
- false
- ],
- "VOSTROM": [
- "VOSTROM Public License for Open Source",
- false
- ],
- "VSL-1.0": [
- "Vovida Software License v1.0",
- true
- ],
- "W3C": [
- "W3C Software Notice and License",
- true
- ],
- "Wsuipa": [
- "Wsuipa License",
- false
- ],
- "WXwindows": [
- "wxWindows Library License",
- true
- ],
- "Xnet": [
- "X.Net License",
- true
- ],
- "X11": [
- "X11 License",
- false
- ],
- "Xerox": [
- "Xerox License",
- false
- ],
- "XFree86-1.1": [
- "XFree86 License 1.1",
- false
- ],
- "xinetd": [
- "xinetd License",
- false
- ],
- "xpp": [
- "XPP License",
- false
- ],
- "XSkat": [
- "XSkat License",
- false
- ],
- "YPL-1.0": [
- "Yahoo! Public License v1.0",
- false
- ],
- "YPL-1.1": [
- "Yahoo! Public License v1.1",
- false
- ],
- "Zed": [
- "Zed License",
- false
- ],
- "Zend-2.0": [
- "Zend License v2.0",
- false
- ],
- "Zimbra-1.3": [
- "Zimbra Public License v1.3",
- false
- ],
- "Zlib": [
- "zlib License",
- true
- ],
- "zlib-acknowledgement": [
- "zlib/libpng License with Acknowledgement",
- false
- ],
- "ZPL-1.1": [
- "Zope Public License 1.1",
- false
- ],
- "ZPL-2.0": [
- "Zope Public License 2.0",
- true
- ],
- "ZPL-2.1": [
- "Zope Public License 2.1",
- false
- ]
-}
\ No newline at end of file
diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php
index 3df98f700..0c32dc750 100644
--- a/src/Composer/Autoload/AutoloadGenerator.php
+++ b/src/Composer/Autoload/AutoloadGenerator.php
@@ -38,8 +38,16 @@ class AutoloadGenerator
*/
private $io;
+ /**
+ * @var bool
+ */
private $devMode = false;
+ /**
+ * @var bool
+ */
+ private $classMapAuthoritative = false;
+
public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null)
{
$this->eventDispatcher = $eventDispatcher;
@@ -51,8 +59,23 @@ class AutoloadGenerator
$this->devMode = (boolean) $devMode;
}
+ /**
+ * Whether or not generated autoloader considers the class map
+ * authoritative.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = (boolean) $classMapAuthoritative;
+ }
+
public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsr0Packages = false, $suffix = '')
{
+ if ($this->classMapAuthoritative) {
+ // Force scanPsr0Packages when classmap is authoritative
+ $scanPsr0Packages = true;
+ }
$this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, array(), array(
'optimize' => (bool) $scanPsr0Packages,
));
@@ -63,7 +86,6 @@ class AutoloadGenerator
$vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
$useGlobalIncludePath = (bool) $config->get('use-include-path');
$prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
- $classMapAuthoritative = $config->get('classmap-authoritative');
$targetDir = $vendorPath.'/'.$targetDir;
$filesystem->ensureDirectoryExists($targetDir);
@@ -174,10 +196,21 @@ EOF;
// flatten array
$classMap = array();
if ($scanPsr0Packages) {
+ $namespacesToScan = array();
+
// Scan the PSR-0/4 directories for class files, and add them to the class map
foreach (array('psr-0', 'psr-4') as $psrType) {
foreach ($autoloads[$psrType] as $namespace => $paths) {
- foreach ($paths as $dir) {
+ $namespacesToScan[$namespace][] = array('paths' => $paths, 'type' => $psrType);
+ }
+ }
+
+ krsort($namespacesToScan);
+
+ foreach ($namespacesToScan as $namespace => $groups) {
+ foreach ($groups as $group) {
+ $psrType = $group['type'];
+ foreach ($group['paths'] as $dir) {
$dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
if (!is_dir($dir)) {
continue;
@@ -190,9 +223,14 @@ EOF;
$namespaceFilter = $namespace === '' ? null : $namespace;
foreach (ClassMapGenerator::createMap($dir, $whitelist, $this->io, $namespaceFilter) as $class => $path) {
+ $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
if (!isset($classMap[$class])) {
- $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
- $classMap[$class] = $path.",\n";
+ $classMap[$class] = $pathCode;
+ } elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
+ $this->io->writeError(
+ 'Warning: Ambiguous class resolution, "'.$class.'"'.
+ ' was found in both "'.str_replace(array('$vendorDir . \'', "',\n"), array($vendorPath, ''), $classMap[$class]).'" and "'.$path.'", the first will be used.'
+ );
}
}
}
@@ -202,8 +240,15 @@ EOF;
foreach ($autoloads['classmap'] as $dir) {
foreach (ClassMapGenerator::createMap($dir, null, $this->io) as $class => $path) {
- $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
- $classMap[$class] = $path.",\n";
+ $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
+ if (!isset($classMap[$class])) {
+ $classMap[$class] = $pathCode;
+ } elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
+ $this->io->writeError(
+ 'Warning: Ambiguous class resolution, "'.$class.'"'.
+ ' was found in both "'.str_replace(array('$vendorDir . \'', "',\n"), array($vendorPath, ''), $classMap[$class]).'" and "'.$path.'", the first will be used.'
+ );
+ }
}
}
@@ -229,23 +274,23 @@ EOF;
file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
file_put_contents($targetDir.'/autoload_psr4.php', $psr4File);
file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);
- if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
- file_put_contents($targetDir.'/include_paths.php', $includePathFile);
+ $includePathFilePath = $targetDir.'/include_paths.php';
+ if ($includePathFileContents = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
+ file_put_contents($includePathFilePath, $includePathFileContents);
+ } elseif (file_exists($includePathFilePath)) {
+ unlink($includePathFilePath);
}
- if ($includeFilesFile = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
- file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile);
+ $includeFilesFilePath = $targetDir.'/autoload_files.php';
+ if ($includeFilesFileContents = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
+ file_put_contents($includeFilesFilePath, $includeFilesFileContents);
+ } elseif (file_exists($includeFilesFilePath)) {
+ unlink($includeFilesFilePath);
}
file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
- file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative));
+ file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader));
- // use stream_copy_to_stream instead of copy
- // to work around https://bugs.php.net/bug.php?id=64634
- $sourceLoader = fopen(__DIR__.'/ClassLoader.php', 'r');
- $targetLoader = fopen($targetDir.'/ClassLoader.php', 'w+');
- stream_copy_to_stream($sourceLoader, $targetLoader);
- fclose($sourceLoader);
- fclose($targetLoader);
- unset($sourceLoader, $targetLoader);
+ $this->safeCopy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
+ $this->safeCopy(__DIR__.'/../../../LICENSE', $targetDir.'/LICENSE');
$this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, array(), array(
'optimize' => (bool) $scanPsr0Packages,
@@ -310,7 +355,7 @@ EOF;
$psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
$psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
- $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage);
+ $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $mainPackage);
$files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
krsort($psr0);
@@ -453,7 +498,7 @@ return ComposerAutoloaderInit$suffix::getLoader();
AUTOLOAD;
}
- protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative)
+ protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader)
{
// TODO the class ComposerAutoloaderInit should be revert to a closure
// when APC has been fixed:
@@ -530,7 +575,7 @@ PSR4;
CLASSMAP;
}
- if ($classMapAuthoritative) {
+ if ($this->classMapAuthoritative) {
$file .= <<<'CLASSMAPAUTHORITATIVE'
$loader->setClassMapAuthoritative(true);
@@ -727,4 +772,20 @@ FOOTER;
return $sortedPackageMap;
}
+
+ /**
+ * Copy file using stream_copy_to_stream to work around https://bugs.php.net/bug.php?id=6463
+ *
+ * @param string $source
+ * @param string $target
+ */
+ protected function safeCopy($source, $target)
+ {
+ $source = fopen($source, 'r');
+ $target = fopen($target, 'w+');
+
+ stream_copy_to_stream($source, $target);
+ fclose($source);
+ fclose($target);
+ }
}
diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php
index 4e05d3b15..5e1469e83 100644
--- a/src/Composer/Autoload/ClassLoader.php
+++ b/src/Composer/Autoload/ClassLoader.php
@@ -351,7 +351,7 @@ class ClassLoader
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
- if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
@@ -361,7 +361,7 @@ class ClassLoader
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
- if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
@@ -380,7 +380,7 @@ class ClassLoader
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
- if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
@@ -390,7 +390,7 @@ class ClassLoader
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
- if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php
index 02b21bd40..5484b7d41 100644
--- a/src/Composer/Autoload/ClassMapGenerator.php
+++ b/src/Composer/Autoload/ClassMapGenerator.php
@@ -49,9 +49,8 @@ class ClassMapGenerator
* @param IOInterface $io IO object
* @param string $namespace Optional namespace prefix to filter by
*
- * @return array A class map array
- *
* @throws \RuntimeException When the path is neither an existing file nor directory
+ * @return array A class map array
*/
public static function createMap($path, $whitelist = null, IOInterface $io = null, $namespace = null)
{
@@ -91,7 +90,7 @@ class ClassMapGenerator
if (!isset($map[$class])) {
$map[$class] = $filePath;
- } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
+ } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
$io->writeError(
'Warning: Ambiguous class resolution, "'.$class.'"'.
' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.'
diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php
index e49edf649..9f9c55ba6 100644
--- a/src/Composer/Cache.php
+++ b/src/Composer/Cache.php
@@ -43,10 +43,12 @@ class Cache
$this->whitelist = $whitelist;
$this->filesystem = $filesystem ?: new Filesystem();
- if (!is_dir($this->root)) {
- if (!@mkdir($this->root, 0777, true)) {
- $this->enabled = false;
- }
+ if (
+ (!is_dir($this->root) && !@mkdir($this->root, 0777, true))
+ || !is_writable($this->root)
+ ) {
+ $this->io->writeError('Cannot create cache directory ' . $this->root . ', or directory is not writable. Proceeding without cache');
+ $this->enabled = false;
}
}
@@ -86,6 +88,9 @@ class Cache
try {
return file_put_contents($this->root . $file, $contents);
} catch (\ErrorException $e) {
+ if ($this->io->isDebug()) {
+ $this->io->writeError('Failed to write into cache: '.$e->getMessage().'');
+ }
if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
// Remove partial file.
unlink($this->root . $file);
diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php
index b7c039510..b8c439678 100644
--- a/src/Composer/Command/ArchiveCommand.php
+++ b/src/Composer/Command/ArchiveCommand.php
@@ -19,7 +19,7 @@ use Composer\Repository\CompositeRepository;
use Composer\Script\ScriptEvents;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
-
+use Composer\Util\Filesystem;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -105,7 +105,12 @@ EOT
}
$io->writeError('Creating the archive into "'.$dest.'".');
- $archiveManager->archive($package, $format, $dest);
+ $packagePath = $archiveManager->archive($package, $format, $dest);
+ $fs = new Filesystem;
+ $shortPath = $fs->findShortestPath(getcwd(), $packagePath, true);
+
+ $io->writeError('Created: ', false);
+ $io->write(strlen($shortPath) < strlen($packagePath) ? $shortPath : $packagePath);
return 0;
}
diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php
index a833a5140..d0f504d9c 100644
--- a/src/Composer/Command/ConfigCommand.php
+++ b/src/Composer/Command/ConfigCommand.php
@@ -66,7 +66,7 @@ class ConfigCommand extends Command
new InputOption('auth', 'a', InputOption::VALUE_NONE, 'Affect auth config file (only used for --editor)'),
new InputOption('unset', null, InputOption::VALUE_NONE, 'Unset the given setting-key'),
new InputOption('list', 'l', InputOption::VALUE_NONE, 'List configuration settings'),
- new InputOption('file', 'f', InputOption::VALUE_REQUIRED, 'If you want to choose a different composer.json or config.json', 'composer.json'),
+ new InputOption('file', 'f', InputOption::VALUE_REQUIRED, 'If you want to choose a different composer.json or config.json'),
new InputOption('absolute', null, InputOption::VALUE_NONE, 'Returns absolute paths when fetching *-dir config values instead of relative'),
new InputArgument('setting-key', null, 'Setting key'),
new InputArgument('setting-value', InputArgument::IS_ARRAY, 'Setting value'),
@@ -129,7 +129,7 @@ EOT
{
parent::initialize($input, $output);
- if ($input->getOption('global') && 'composer.json' !== $input->getOption('file')) {
+ if ($input->getOption('global') && null !== $input->getOption('file')) {
throw new \RuntimeException('--file and --global can not be combined');
}
@@ -139,7 +139,7 @@ EOT
// passed in a file to use
$configFile = $input->getOption('global')
? ($this->config->get('home') . '/config.json')
- : $input->getOption('file');
+ : ($input->getOption('file') ?: trim(getenv('COMPOSER')) ?: 'composer.json');
// create global composer.json if this was invoked using `composer global config`
if ($configFile === 'composer.json' && !file_exists($configFile) && realpath(getcwd()) === realpath($this->config->get('home'))) {
@@ -151,7 +151,7 @@ EOT
$authConfigFile = $input->getOption('global')
? ($this->config->get('home') . '/auth.json')
- : dirname(realpath($input->getOption('file'))) . '/auth.json';
+ : dirname(realpath($configFile)) . '/auth.json';
$this->authConfigFile = new JsonFile($authConfigFile);
$this->authConfigSource = new JsonConfigSource($this->authConfigFile, true);
@@ -238,17 +238,19 @@ EOT
} elseif (strpos($settingKey, '.')) {
$bits = explode('.', $settingKey);
$data = $data['config'];
+ $match = false;
foreach ($bits as $bit) {
- if (isset($data[$bit])) {
- $data = $data[$bit];
- } elseif (isset($data[implode('.', $bits)])) {
- // last bit can contain domain names and such so try to join whatever is left if it exists
- $data = $data[implode('.', $bits)];
- break;
- } else {
- throw new \RuntimeException($settingKey.' is not defined');
+ $key = isset($key) ? $key.'.'.$bit : $bit;
+ $match = false;
+ if (isset($data[$key])) {
+ $match = true;
+ $data = $data[$key];
+ unset($key);
}
- array_shift($bits);
+ }
+
+ if (!$match) {
+ throw new \RuntimeException($settingKey.' is not defined.');
}
$value = $data;
@@ -278,7 +280,7 @@ EOT
'use-include-path' => array($booleanValidator, $booleanNormalizer),
'preferred-install' => array(
function ($val) { return in_array($val, array('auto', 'source', 'dist'), true); },
- function ($val) { return $val; }
+ function ($val) { return $val; },
),
'store-auths' => array(
function ($val) { return in_array($val, array('true', 'false', 'prompt'), true); },
@@ -288,7 +290,7 @@ EOT
}
return $val !== 'false' && (bool) $val;
- }
+ },
),
'notify-on-install' => array($booleanValidator, $booleanNormalizer),
'vendor-dir' => array('is_string', function ($val) { return $val; }),
@@ -301,7 +303,7 @@ EOT
'cache-files-ttl' => array('is_numeric', 'intval'),
'cache-files-maxsize' => array(
function ($val) { return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; },
- function ($val) { return $val; }
+ function ($val) { return $val; },
),
'discard-changes' => array(
function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); },
@@ -311,7 +313,7 @@ EOT
}
return $val !== 'false' && (bool) $val;
- }
+ },
),
'autoloader-suffix' => array('is_string', function ($val) { return $val === 'null' ? null : $val; }),
'optimize-autoloader' => array($booleanValidator, $booleanNormalizer),
@@ -336,7 +338,7 @@ EOT
},
function ($vals) {
return $vals;
- }
+ },
),
'github-domains' => array(
function ($vals) {
@@ -348,7 +350,7 @@ EOT
},
function ($vals) {
return $vals;
- }
+ },
),
);
@@ -464,6 +466,7 @@ EOT
protected function listConfiguration(array $contents, array $rawContents, OutputInterface $output, $k = null)
{
$origK = $k;
+ $io = $this->getIO();
foreach ($contents as $key => $value) {
if ($k === null && !in_array($key, array('config', 'repositories'))) {
continue;
@@ -474,13 +477,7 @@ EOT
if (is_array($value) && (!is_numeric(key($value)) || ($key === 'repositories' && null === $k))) {
$k .= preg_replace('{^config\.}', '', $key . '.');
$this->listConfiguration($value, $rawVal, $output, $k);
-
- if (substr_count($k, '.') > 1) {
- $k = str_split($k, strrpos($k, '.', -2));
- $k = $k[0] . '.';
- } else {
- $k = $origK;
- }
+ $k = $origK;
continue;
}
@@ -498,9 +495,9 @@ EOT
}
if (is_string($rawVal) && $rawVal != $value) {
- $this->getIO()->write('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')');
+ $io->write('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')');
} else {
- $this->getIO()->write('[' . $k . $key . '] ' . $value . '');
+ $io->write('[' . $k . $key . '] ' . $value . '');
}
}
}
diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php
index 02aaf6f1b..2cae1414a 100644
--- a/src/Composer/Command/CreateProjectCommand.php
+++ b/src/Composer/Command/CreateProjectCommand.php
@@ -100,16 +100,17 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$config = Factory::createConfig();
+ $io = $this->getIO();
$this->updatePreferredOptions($config, $input, $preferSource, $preferDist, true);
if ($input->getOption('no-custom-installers')) {
- $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
+ $io->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
$input->setOption('no-plugins', true);
}
return $this->installProject(
- $this->getIO(),
+ $io,
$config,
$input->getArgument('package'),
$input->getArgument('directory'),
@@ -290,15 +291,15 @@ EOT
// handler Ctrl+C for unix-like systems
if (function_exists('pcntl_signal')) {
- declare(ticks = 100);
- pcntl_signal(SIGINT, function() use ($directory) {
+ declare (ticks = 100);
+ pcntl_signal(SIGINT, function () use ($directory) {
$fs = new Filesystem();
$fs->removeDirectory($directory);
exit(130);
});
}
- $io->writeError('Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')');
+ $io->writeError('Installing ' . $package->getName() . ' (' . $package->getFullPrettyVersion(false) . ')');
if ($disablePlugins) {
$io->writeError('Plugins have been disabled.');
@@ -346,8 +347,8 @@ EOT
* Updated preferSource or preferDist based on the preferredInstall config option
* @param Config $config
* @param InputInterface $input
- * @param boolean $preferSource
- * @param boolean $preferDist
+ * @param bool $preferSource
+ * @param bool $preferDist
*/
protected function updatePreferredOptions(Config $config, InputInterface $input, &$preferSource, &$preferDist, $keepVcsRequiresPreferSource = false)
{
diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php
index 97b9d0f39..b4017c2fe 100644
--- a/src/Composer/Command/DependsCommand.php
+++ b/src/Composer/Command/DependsCommand.php
@@ -81,6 +81,7 @@ EOT
$messages = array();
$outputPackages = array();
+ $io = $this->getIO();
foreach ($repo->getPackages() as $package) {
foreach ($types as $type) {
foreach ($package->{'get'.$linkTypes[$type][0]}() as $link) {
@@ -96,9 +97,9 @@ EOT
if ($messages) {
sort($messages);
- $this->getIO()->write($messages);
+ $io->write($messages);
} else {
- $this->getIO()->writeError('There is no installed package depending on "'.$needle.'".');
+ $io->writeError('There is no installed package depending on "'.$needle.'".');
}
}
}
diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php
index c279d182c..afca401b6 100644
--- a/src/Composer/Command/DiagnoseCommand.php
+++ b/src/Composer/Command/DiagnoseCommand.php
@@ -57,12 +57,13 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$composer = $this->getComposer(false);
+ $io = $this->getIO();
if ($composer) {
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
- $this->getIO()->write('Checking composer.json: ', false);
+ $io->write('Checking composer.json: ', false);
$this->outputResult($this->checkComposerSchema());
}
@@ -72,44 +73,44 @@ EOT
$config = Factory::createConfig();
}
- $this->rfs = new RemoteFilesystem($this->getIO(), $config);
- $this->process = new ProcessExecutor($this->getIO());
+ $this->rfs = new RemoteFilesystem($io, $config);
+ $this->process = new ProcessExecutor($io);
- $this->getIO()->write('Checking platform settings: ', false);
+ $io->write('Checking platform settings: ', false);
$this->outputResult($this->checkPlatform());
- $this->getIO()->write('Checking git settings: ', false);
+ $io->write('Checking git settings: ', false);
$this->outputResult($this->checkGit());
- $this->getIO()->write('Checking http connectivity to packagist: ', false);
+ $io->write('Checking http connectivity to packagist: ', false);
$this->outputResult($this->checkHttp('http'));
- $this->getIO()->write('Checking https connectivity to packagist: ', false);
+ $io->write('Checking https connectivity to packagist: ', false);
$this->outputResult($this->checkHttp('https'));
$opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org'));
if (!empty($opts['http']['proxy'])) {
- $this->getIO()->write('Checking HTTP proxy: ', false);
+ $io->write('Checking HTTP proxy: ', false);
$this->outputResult($this->checkHttpProxy());
- $this->getIO()->write('Checking HTTP proxy support for request_fulluri: ', false);
+ $io->write('Checking HTTP proxy support for request_fulluri: ', false);
$this->outputResult($this->checkHttpProxyFullUriRequestParam());
- $this->getIO()->write('Checking HTTPS proxy support for request_fulluri: ', false);
+ $io->write('Checking HTTPS proxy support for request_fulluri: ', false);
$this->outputResult($this->checkHttpsProxyFullUriRequestParam());
}
if ($oauth = $config->get('github-oauth')) {
foreach ($oauth as $domain => $token) {
- $this->getIO()->write('Checking '.$domain.' oauth access: ', false);
+ $io->write('Checking '.$domain.' oauth access: ', false);
$this->outputResult($this->checkGithubOauth($domain, $token));
}
} else {
- $this->getIO()->write('Checking github.com rate limit: ', false);
+ $io->write('Checking github.com rate limit: ', false);
try {
$rate = $this->getGithubRateLimit('github.com');
$this->outputResult(true);
if (10 > $rate['remaining']) {
- $this->getIO()->write('WARNING');
- $this->getIO()->write(sprintf(
+ $io->write('WARNING');
+ $io->write(sprintf(
'Github has a rate limit on their API. '
. 'You currently have %u '
. 'out of %u requests left.' . PHP_EOL
@@ -128,10 +129,10 @@ EOT
}
}
- $this->getIO()->write('Checking disk free space: ', false);
+ $io->write('Checking disk free space: ', false);
$this->outputResult($this->checkDiskSpace($config));
- $this->getIO()->write('Checking composer version: ', false);
+ $io->write('Checking composer version: ', false);
$this->outputResult($this->checkVersion());
return $this->failures;
@@ -263,7 +264,7 @@ EOT
$url = $domain === 'github.com' ? 'https://api.'.$domain.'/user/repos' : 'https://'.$domain.'/api/v3/user/repos';
return $this->rfs->getContents($domain, $url, false, array(
- 'retry-auth-failure' => false
+ 'retry-auth-failure' => false,
)) ? true : 'Unexpected error';
} catch (\Exception $e) {
if ($e instanceof TransportException && $e->getCode() === 401) {
@@ -275,10 +276,10 @@ EOT
}
/**
- * @param string $domain
- * @param string $token
- * @return array
+ * @param string $domain
+ * @param string $token
* @throws TransportException
+ * @return array
*/
private function getGithubRateLimit($domain, $token = null)
{
@@ -295,7 +296,7 @@ EOT
private function checkDiskSpace($config)
{
- $minSpaceFree = 1024*1024;
+ $minSpaceFree = 1024 * 1024;
if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
|| (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
) {
@@ -322,15 +323,16 @@ EOT
*/
private function outputResult($result)
{
+ $io = $this->getIO();
if (true === $result) {
- $this->getIO()->write('OK');
+ $io->write('OK');
} else {
$this->failures++;
- $this->getIO()->write('FAIL');
+ $io->write('FAIL');
if ($result instanceof \Exception) {
- $this->getIO()->write('['.get_class($result).'] '.$result->getMessage());
+ $io->write('['.get_class($result).'] '.$result->getMessage());
} elseif ($result) {
- $this->getIO()->write(trim($result));
+ $io->write(trim($result));
}
}
}
diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php
index f560953b8..c452d1fb4 100644
--- a/src/Composer/Command/DumpAutoloadCommand.php
+++ b/src/Composer/Command/DumpAutoloadCommand.php
@@ -31,6 +31,7 @@ class DumpAutoloadCommand extends Command
->setDescription('Dumps the autoloader')
->setDefinition(array(
new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'),
+ new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'),
))
->setHelp(<<getPackage();
$config = $composer->getConfig();
- $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
+ $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader');
+ $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
- if ($optimize) {
+ if ($optimize || $authoritative) {
$this->getIO()->writeError('Generating optimized autoload files');
} else {
$this->getIO()->writeError('Generating autoload files');
@@ -62,6 +64,7 @@ EOT
$generator = $composer->getAutoloadGenerator();
$generator->setDevMode(!$input->getOption('no-dev'));
+ $generator->setClassMapAuthoritative($authoritative);
$generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
}
}
diff --git a/src/Composer/Command/HomeCommand.php b/src/Composer/Command/HomeCommand.php
index b20e661f9..fff1f86eb 100644
--- a/src/Composer/Command/HomeCommand.php
+++ b/src/Composer/Command/HomeCommand.php
@@ -14,7 +14,6 @@ namespace Composer\Command;
use Composer\Factory;
use Composer\Package\CompletePackageInterface;
-use Composer\Repository\CompositeRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\ArrayRepository;
use Composer\Util\ProcessExecutor;
@@ -58,6 +57,7 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$repos = $this->initializeRepos();
+ $io = $this->getIO();
$return = 0;
foreach ($input->getArgument('packages') as $packageName) {
@@ -75,12 +75,12 @@ EOT
if (!$packageExists) {
$return = 1;
- $this->getIO()->writeError('Package '.$packageName.' not found');
+ $io->writeError('Package '.$packageName.' not found');
}
if (!$handled) {
$return = 1;
- $this->getIO()->writeError(''.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'');
+ $io->writeError(''.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'');
}
}
diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php
index 971477306..795d72958 100644
--- a/src/Composer/Command/InitCommand.php
+++ b/src/Composer/Command/InitCommand.php
@@ -16,10 +16,10 @@ use Composer\DependencyResolver\Pool;
use Composer\Json\JsonFile;
use Composer\Factory;
use Composer\Package\BasePackage;
+use Composer\Package\Version\VersionParser;
use Composer\Package\Version\VersionSelector;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
-use Composer\Package\Version\VersionParser;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -106,11 +106,12 @@ EOT
$file = new JsonFile('composer.json');
$json = $file->encode($options);
+ $io = $this->getIO();
if ($input->isInteractive()) {
- $this->getIO()->writeError(array('', $json, ''));
- if (!$this->getIO()->askConfirmation('Do you confirm generation [yes]? ', true)) {
- $this->getIO()->writeError('Command aborted');
+ $io->writeError(array('', $json, ''));
+ if (!$io->askConfirmation('Do you confirm generation [yes]? ', true)) {
+ $io->writeError('Command aborted');
return 1;
}
@@ -128,7 +129,7 @@ EOT
if (!$this->hasVendorIgnore($ignoreFile)) {
$question = 'Would you like the vendor directory added to your .gitignore [yes]? ';
- if ($this->getIO()->askConfirmation($question, true)) {
+ if ($io->askConfirmation($question, true)) {
$this->addVendorIgnore($ignoreFile);
}
}
@@ -141,17 +142,17 @@ EOT
protected function interact(InputInterface $input, OutputInterface $output)
{
$git = $this->getGitConfig();
-
+ $io = $this->getIO();
$formatter = $this->getHelperSet()->get('formatter');
- $this->getIO()->writeError(array(
+ $io->writeError(array(
'',
$formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
- ''
+ '',
));
// namespace
- $this->getIO()->writeError(array(
+ $io->writeError(array(
'',
'This command will guide you through creating your composer.json config.',
'',
@@ -181,7 +182,7 @@ EOT
}
}
- $name = $this->getIO()->askAndValidate(
+ $name = $io->askAndValidate(
'Package name (/) ['.$name.']: ',
function ($value) use ($name) {
if (null === $value) {
@@ -202,7 +203,7 @@ EOT
$input->setOption('name', $name);
$description = $input->getOption('description') ?: false;
- $description = $this->getIO()->ask(
+ $description = $io->ask(
'Description ['.$description.']: ',
$description
);
@@ -215,7 +216,7 @@ EOT
}
$self = $this;
- $author = $this->getIO()->askAndValidate(
+ $author = $io->askAndValidate(
'Author ['.$author.']: ',
function ($value) use ($self, $author) {
$value = $value ?: $author;
@@ -229,7 +230,7 @@ EOT
$input->setOption('author', $author);
$minimumStability = $input->getOption('stability') ?: null;
- $minimumStability = $this->getIO()->askAndValidate(
+ $minimumStability = $io->askAndValidate(
'Minimum Stability ['.$minimumStability.']: ',
function ($value) use ($self, $minimumStability) {
if (null === $value) {
@@ -251,31 +252,31 @@ EOT
$input->setOption('stability', $minimumStability);
$type = $input->getOption('type') ?: false;
- $type = $this->getIO()->ask(
+ $type = $io->ask(
'Package Type ['.$type.']: ',
$type
);
$input->setOption('type', $type);
$license = $input->getOption('license') ?: false;
- $license = $this->getIO()->ask(
+ $license = $io->ask(
'License ['.$license.']: ',
$license
);
$input->setOption('license', $license);
- $this->getIO()->writeError(array('', 'Define your dependencies.', ''));
+ $io->writeError(array('', 'Define your dependencies.', ''));
$question = 'Would you like to define your dependencies (require) interactively [yes]? ';
$requirements = array();
- if ($this->getIO()->askConfirmation($question, true)) {
+ if ($io->askConfirmation($question, true)) {
$requirements = $this->determineRequirements($input, $output, $input->getOption('require'));
}
$input->setOption('require', $requirements);
$question = 'Would you like to define your dev dependencies (require-dev) interactively [yes]? ';
$devRequirements = array();
- if ($this->getIO()->askConfirmation($question, true)) {
+ if ($io->askConfirmation($question, true)) {
$devRequirements = $this->determineRequirements($input, $output, $input->getOption('require-dev'));
}
$input->setOption('require-dev', $devRequirements);
@@ -283,7 +284,7 @@ EOT
/**
* @private
- * @param string $author
+ * @param string $author
* @return array
*/
public function parseAuthorString($author)
@@ -292,7 +293,7 @@ EOT
if ($this->isValidEmail($match['email'])) {
return array(
'name' => trim($match['name']),
- 'email' => $match['email']
+ 'email' => $match['email'],
);
}
}
@@ -325,6 +326,7 @@ EOT
if ($requires) {
$requires = $this->normalizeRequirements($requires);
$result = array();
+ $io = $this->getIO();
foreach ($requires as $requirement) {
if (!isset($requirement['version'])) {
@@ -332,7 +334,7 @@ EOT
$version = $this->findBestVersionForPackage($input, $requirement['name']);
$requirement['version'] = $version;
- $this->getIO()->writeError(sprintf(
+ $io->writeError(sprintf(
'Using version %s for %s',
$requirement['version'],
$requirement['name']
@@ -346,7 +348,8 @@ EOT
}
$versionParser = new VersionParser();
- while (null !== $package = $this->getIO()->ask('Search for a package: ')) {
+ $io = $this->getIO();
+ while (null !== $package = $io->ask('Search for a package: ')) {
$matches = $this->findPackages($package);
if (count($matches)) {
@@ -362,14 +365,14 @@ EOT
// no match, prompt which to pick
if (!$exactMatch) {
- $this->getIO()->writeError(array(
+ $io->writeError(array(
'',
sprintf('Found %s packages matching %s', count($matches), $package),
- ''
+ '',
));
- $this->getIO()->writeError($choices);
- $this->getIO()->writeError('');
+ $io->writeError($choices);
+ $io->writeError('');
$validator = function ($selection) use ($matches, $versionParser) {
if ('' === $selection) {
@@ -399,7 +402,7 @@ EOT
throw new \Exception('Not a valid selection');
};
- $package = $this->getIO()->askAndValidate(
+ $package = $io->askAndValidate(
'Enter package # to add, or the complete package name if it is not listed: ',
$validator,
3,
@@ -415,7 +418,7 @@ EOT
return $input ?: false;
};
- $constraint = $this->getIO()->askAndValidate(
+ $constraint = $io->askAndValidate(
'Enter the version constraint to require (or leave blank to use the latest version): ',
$validator,
3,
@@ -425,7 +428,7 @@ EOT
if (false === $constraint) {
$constraint = $this->findBestVersionForPackage($input, $package);
- $this->getIO()->writeError(sprintf(
+ $io->writeError(sprintf(
'Using version %s for %s',
$constraint,
$package
@@ -588,8 +591,8 @@ EOT
*
* @param InputInterface $input
* @param string $name
- * @return string
* @throws \InvalidArgumentException
+ * @return string
*/
private function findBestVersionForPackage(InputInterface $input, $name)
{
diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php
index e548b8d69..3ae00c228 100644
--- a/src/Composer/Command/InstallCommand.php
+++ b/src/Composer/Command/InstallCommand.php
@@ -46,6 +46,7 @@ class InstallCommand extends Command
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
+ new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'),
))
@@ -64,24 +65,24 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = $this->getIO();
if ($args = $input->getArgument('packages')) {
- $this->getIO()->writeError('Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.');
+ $io->writeError('Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.');
return 1;
}
if ($input->getOption('no-custom-installers')) {
- $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
+ $io->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
$input->setOption('no-plugins', true);
}
if ($input->getOption('dev')) {
- $this->getIO()->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.');
+ $io->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.');
}
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
- $io = $this->getIO();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@@ -110,7 +111,8 @@ EOT
$preferDist = $input->getOption('prefer-dist');
}
- $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
+ $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
+ $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
$install
->setDryRun($input->getOption('dry-run'))
@@ -121,6 +123,7 @@ EOT
->setDumpAutoloader(!$input->getOption('no-autoloader'))
->setRunScripts(!$input->getOption('no-scripts'))
->setOptimizeAutoloader($optimize)
+ ->setClassMapAuthoritative($authoritative)
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
;
diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php
index ddeabf00f..b542c3fe6 100644
--- a/src/Composer/Command/LicensesCommand.php
+++ b/src/Composer/Command/LicensesCommand.php
@@ -13,7 +13,6 @@
namespace Composer\Command;
use Composer\Json\JsonFile;
-use Composer\Package\Version\VersionParser;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Package\PackageInterface;
@@ -56,8 +55,6 @@ EOT
$root = $composer->getPackage();
$repo = $composer->getRepositoryManager()->getLocalRepository();
- $versionParser = new VersionParser;
-
if ($input->getOption('no-dev')) {
$packages = $this->filterRequiredPackages($repo, $root);
} else {
@@ -65,14 +62,15 @@ EOT
}
ksort($packages);
+ $io = $this->getIO();
switch ($format = $input->getOption('format')) {
case 'text':
- $this->getIO()->write('Name: '.$root->getPrettyName().'');
- $this->getIO()->write('Version: '.$versionParser->formatVersion($root).'');
- $this->getIO()->write('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').'');
- $this->getIO()->write('Dependencies:');
- $this->getIO()->write('');
+ $io->write('Name: '.$root->getPrettyName().'');
+ $io->write('Version: '.$root->getFullPrettyVersion().'');
+ $io->write('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').'');
+ $io->write('Dependencies:');
+ $io->write('');
$table = new Table($output);
$table->setStyle('compact');
@@ -82,7 +80,7 @@ EOT
foreach ($packages as $package) {
$table->addRow(array(
$package->getPrettyName(),
- $versionParser->formatVersion($package),
+ $package->getFullPrettyVersion(),
implode(', ', $package->getLicense()) ?: 'none',
));
}
@@ -92,14 +90,14 @@ EOT
case 'json':
foreach ($packages as $package) {
$dependencies[$package->getPrettyName()] = array(
- 'version' => $versionParser->formatVersion($package),
+ 'version' => $package->getFullPrettyVersion(),
'license' => $package->getLicense(),
);
}
- $this->getIO()->write(JsonFile::encode(array(
+ $io->write(JsonFile::encode(array(
'name' => $root->getPrettyName(),
- 'version' => $versionParser->formatVersion($root),
+ 'version' => $root->getFullPrettyVersion(),
'license' => $root->getLicense(),
'dependencies' => $dependencies,
)));
diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php
index 3779b09e9..869720718 100644
--- a/src/Composer/Command/RemoveCommand.php
+++ b/src/Composer/Command/RemoveCommand.php
@@ -42,6 +42,8 @@ class RemoveCommand extends Command
new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
+ new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
+ new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
))
->setHelp(<<remove command removes a package from the current
@@ -68,19 +70,20 @@ EOT
$type = $input->getOption('dev') ? 'require-dev' : 'require';
$altType = !$input->getOption('dev') ? 'require-dev' : 'require';
+ $io = $this->getIO();
foreach ($packages as $package) {
if (isset($composer[$type][$package])) {
$json->removeLink($type, $package);
} elseif (isset($composer[$altType][$package])) {
- $this->getIO()->writeError(''.$package.' could not be found in '.$type.' but it is present in '.$altType.'');
- if ($this->getIO()->isInteractive()) {
- if ($this->getIO()->askConfirmation('Do you want to remove it from '.$altType.' [yes]? ', true)) {
+ $io->writeError(''.$package.' could not be found in '.$type.' but it is present in '.$altType.'');
+ if ($io->isInteractive()) {
+ if ($io->askConfirmation('Do you want to remove it from '.$altType.' [yes]? ', true)) {
$json->removeLink($altType, $package);
}
}
} else {
- $this->getIO()->writeError(''.$package.' is not required in your composer.json and has not been removed');
+ $io->writeError(''.$package.' is not required in your composer.json and has not been removed');
}
}
@@ -91,7 +94,6 @@ EOT
// Update packages
$composer = $this->getComposer();
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
- $io = $this->getIO();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@@ -99,9 +101,14 @@ EOT
$install = Installer::create($io, $composer);
$updateDevMode = !$input->getOption('update-no-dev');
+ $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
+ $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
+
$install
->setVerbose($input->getOption('verbose'))
->setDevMode($updateDevMode)
+ ->setOptimizeAutoloader($optimize)
+ ->setClassMapAuthoritative($authoritative)
->setUpdate(true)
->setUpdateWhitelist($packages)
->setWhitelistDependencies($input->getOption('update-with-dependencies'))
@@ -110,7 +117,7 @@ EOT
$status = $install->run();
if ($status !== 0) {
- $this->getIO()->writeError("\n".'Removal failed, reverting '.$file.' to its original content.');
+ $io->writeError("\n".'Removal failed, reverting '.$file.' to its original content.');
file_put_contents($jsonFile->getPath(), $composerBackup);
}
diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php
index 82401ffb2..c7bcc8735 100644
--- a/src/Composer/Command/RequireCommand.php
+++ b/src/Composer/Command/RequireCommand.php
@@ -20,7 +20,7 @@ use Composer\Factory;
use Composer\Installer;
use Composer\Json\JsonFile;
use Composer\Json\JsonManipulator;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Repository\CompositeRepository;
@@ -48,6 +48,8 @@ class RequireCommand extends InitCommand
new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'),
+ new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
+ new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
))
->setHelp(<<getIO();
$newlyCreated = !file_exists($file);
if (!file_exists($file) && !file_put_contents($file, "{\n}\n")) {
- $this->getIO()->writeError(''.$file.' could not be created.');
+ $io->writeError(''.$file.' could not be created.');
return 1;
}
if (!is_readable($file)) {
- $this->getIO()->writeError(''.$file.' is not readable.');
+ $io->writeError(''.$file.' is not readable.');
return 1;
}
if (!is_writable($file)) {
- $this->getIO()->writeError(''.$file.' is not writable.');
+ $io->writeError(''.$file.' is not writable.');
return 1;
}
@@ -126,18 +129,19 @@ EOT
$json->write($composerDefinition);
}
- $this->getIO()->writeError(''.$file.' has been '.($newlyCreated ? 'created' : 'updated').'');
+ $io->writeError(''.$file.' has been '.($newlyCreated ? 'created' : 'updated').'');
if ($input->getOption('no-update')) {
return 0;
}
$updateDevMode = !$input->getOption('update-no-dev');
+ $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
+ $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
// Update packages
$this->resetComposer();
$composer = $this->getComposer();
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
- $io = $this->getIO();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@@ -149,6 +153,8 @@ EOT
->setPreferSource($input->getOption('prefer-source'))
->setPreferDist($input->getOption('prefer-dist'))
->setDevMode($updateDevMode)
+ ->setOptimizeAutoloader($optimize)
+ ->setClassMapAuthoritative($authoritative)
->setUpdate(true)
->setUpdateWhitelist(array_keys($requirements))
->setWhitelistDependencies($input->getOption('update-with-dependencies'))
@@ -158,10 +164,10 @@ EOT
$status = $install->run();
if ($status !== 0) {
if ($newlyCreated) {
- $this->getIO()->writeError("\n".'Installation failed, deleting '.$file.'.');
+ $io->writeError("\n".'Installation failed, deleting '.$file.'.');
unlink($json->getPath());
} else {
- $this->getIO()->writeError("\n".'Installation failed, reverting '.$file.' to its original content.');
+ $io->writeError("\n".'Installation failed, reverting '.$file.' to its original content.');
file_put_contents($json->getPath(), $composerBackup);
}
}
diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php
index 8b5b13d2a..5ad87bf40 100644
--- a/src/Composer/Command/RunScriptCommand.php
+++ b/src/Composer/Command/RunScriptCommand.php
@@ -104,9 +104,10 @@ EOT
return 0;
}
- $this->getIO()->writeError('scripts:');
+ $io = $this->getIO();
+ $io->writeError('scripts:');
foreach ($scripts as $name => $script) {
- $this->getIO()->write(' ' . $name);
+ $io->write(' ' . $name);
}
return 0;
diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php
index 54990f30d..e636fc4d0 100644
--- a/src/Composer/Command/SearchCommand.php
+++ b/src/Composer/Command/SearchCommand.php
@@ -56,13 +56,14 @@ EOT
{
// init repos
$platformRepo = new PlatformRepository;
+ $io = $this->getIO();
if ($composer = $this->getComposer(false)) {
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
$installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
$repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
} else {
- $defaultRepos = Factory::createDefaultRepositories($this->getIO());
- $this->getIO()->writeError('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
+ $defaultRepos = Factory::createDefaultRepositories($io);
+ $io->writeError('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
$installedRepo = $platformRepo;
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
}
@@ -78,7 +79,7 @@ EOT
$results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags);
foreach ($results as $result) {
- $this->getIO()->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
+ $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
}
}
}
diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php
index eed811c13..6b85e000d 100644
--- a/src/Composer/Command/SelfUpdateCommand.php
+++ b/src/Composer/Command/SelfUpdateCommand.php
@@ -60,7 +60,8 @@ EOT
{
$baseUrl = (extension_loaded('openssl') ? 'https' : 'http') . '://' . self::HOMEPAGE;
$config = Factory::createConfig();
- $remoteFilesystem = new RemoteFilesystem($this->getIO(), $config);
+ $io = $this->getIO();
+ $remoteFilesystem = new RemoteFilesystem($io, $config);
$cacheDir = $config->get('cache-dir');
$rollbackDir = $config->get('data-dir');
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
@@ -84,13 +85,13 @@ EOT
$updateVersion = $input->getArgument('version') ?: $latestVersion;
if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) {
- $this->getIO()->writeError('You can not update to a specific SHA-1 as those phars are not available for download');
+ $io->writeError('You can not update to a specific SHA-1 as those phars are not available for download');
return 1;
}
if (Composer::VERSION === $updateVersion) {
- $this->getIO()->writeError('You are already using composer version '.$updateVersion.'.');
+ $io->writeError('You are already using composer version '.$updateVersion.'.');
return 0;
}
@@ -104,11 +105,11 @@ EOT
self::OLD_INSTALL_EXT
);
- $this->getIO()->writeError(sprintf("Updating to version %s.", $updateVersion));
+ $io->writeError(sprintf("Updating to version %s.", $updateVersion));
$remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar");
$remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress'));
if (!file_exists($tempFilename)) {
- $this->getIO()->writeError('The download of the new composer version failed for an unexpected reason');
+ $io->writeError('The download of the new composer version failed for an unexpected reason');
return 1;
}
@@ -120,22 +121,22 @@ EOT
$fs = new Filesystem;
foreach ($finder as $file) {
$file = (string) $file;
- $this->getIO()->writeError('Removing: '.$file.'');
+ $io->writeError('Removing: '.$file.'');
$fs->remove($file);
}
}
if ($err = $this->setLocalPhar($localFilename, $tempFilename, $backupFile)) {
- $this->getIO()->writeError('The file is corrupted ('.$err->getMessage().').');
- $this->getIO()->writeError('Please re-run the self-update command to try again.');
+ $io->writeError('The file is corrupted ('.$err->getMessage().').');
+ $io->writeError('Please re-run the self-update command to try again.');
return 1;
}
if (file_exists($backupFile)) {
- $this->getIO()->writeError('Use composer self-update --rollback to return to version '.Composer::VERSION);
+ $io->writeError('Use composer self-update --rollback to return to version '.Composer::VERSION);
} else {
- $this->getIO()->writeError('A backup of the current version could not be written to '.$backupFile.', no rollback possible');
+ $io->writeError('A backup of the current version could not be written to '.$backupFile.', no rollback possible');
}
}
@@ -160,9 +161,10 @@ EOT
}
$oldFile = $rollbackDir . "/{$rollbackVersion}" . self::OLD_INSTALL_EXT;
- $this->getIO()->writeError(sprintf("Rolling back to version %s.", $rollbackVersion));
+ $io = $this->getIO();
+ $io->writeError(sprintf("Rolling back to version %s.", $rollbackVersion));
if ($err = $this->setLocalPhar($localFilename, $oldFile)) {
- $this->getIO()->writeError('The backup file was corrupted ('.$err->getMessage().') and has been removed.');
+ $io->writeError('The backup file was corrupted ('.$err->getMessage().') and has been removed.');
return 1;
}
diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php
index b4f5de49b..8aa6de5ca 100644
--- a/src/Composer/Command/ShowCommand.php
+++ b/src/Composer/Command/ShowCommand.php
@@ -16,7 +16,7 @@ use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\DefaultPolicy;
use Composer\Factory;
use Composer\Package\CompletePackageInterface;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Symfony\Component\Console\Input\InputInterface;
@@ -28,7 +28,7 @@ use Composer\Repository\CompositeRepository;
use Composer\Repository\ComposerRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
-use Composer\Util\SpdxLicense;
+use Composer\Spdx\SpdxLicenses;
/**
* @author Robert Schönthal
@@ -71,6 +71,7 @@ EOT
$platformRepo = new PlatformRepository;
$composer = $this->getComposer(false);
+ $io = $this->getIO();
if ($input->getOption('self')) {
$package = $this->getComposer()->getPackage();
$repos = $installedRepo = new ArrayRepository(array($package));
@@ -83,17 +84,17 @@ EOT
if ($composer) {
$repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
} else {
- $defaultRepos = Factory::createDefaultRepositories($this->getIO());
+ $defaultRepos = Factory::createDefaultRepositories($io);
$repos = new CompositeRepository($defaultRepos);
- $this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
+ $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
}
} elseif ($composer) {
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
$installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
$repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
} else {
- $defaultRepos = Factory::createDefaultRepositories($this->getIO());
- $this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
+ $defaultRepos = Factory::createDefaultRepositories($io);
+ $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
$installedRepo = $platformRepo;
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
}
@@ -120,9 +121,9 @@ EOT
$this->printLinks($package, 'requires');
$this->printLinks($package, 'devRequires', 'requires (dev)');
if ($package->getSuggests()) {
- $this->getIO()->write("\nsuggests");
+ $io->write("\nsuggests");
foreach ($package->getSuggests() as $suggested => $reason) {
- $this->getIO()->write($suggested . ' ' . $reason . '');
+ $io->write($suggested . ' ' . $reason . '');
}
}
$this->printLinks($package, 'provides');
@@ -173,7 +174,7 @@ EOT
foreach (array('platform:' => true, 'available:' => false, 'installed:' => true) as $type => $showVersion) {
if (isset($packages[$type])) {
if ($tree) {
- $this->getIO()->write($type);
+ $io->write($type);
}
ksort($packages[$type]);
@@ -181,7 +182,7 @@ EOT
foreach ($packages[$type] as $package) {
if (is_object($package)) {
$nameLength = max($nameLength, strlen($package->getPrettyName()));
- $versionLength = max($versionLength, strlen($this->versionParser->formatVersion($package)));
+ $versionLength = max($versionLength, strlen($package->getFullPrettyVersion()));
} else {
$nameLength = max($nameLength, $package);
}
@@ -197,7 +198,7 @@ EOT
}
if ($input->getOption('path') && null === $composer) {
- $this->getIO()->writeError('No composer.json found in the current directory, disabling "path" option');
+ $io->writeError('No composer.json found in the current directory, disabling "path" option');
$input->setOption('path', false);
}
@@ -209,7 +210,7 @@ EOT
$output->write($indent . str_pad($package->getPrettyName(), $nameLength, ' '), false);
if ($writeVersion) {
- $output->write(' ' . str_pad($this->versionParser->formatVersion($package), $versionLength, ' '), false);
+ $output->write(' ' . str_pad($package->getFullPrettyVersion(), $versionLength, ' '), false);
}
if ($writeDescription) {
@@ -228,10 +229,10 @@ EOT
} else {
$output->write($indent . $package);
}
- $this->getIO()->write('');
+ $io->write('');
}
if ($tree) {
- $this->getIO()->write('');
+ $io->write('');
}
}
}
@@ -244,8 +245,8 @@ EOT
* @param RepositoryInterface $repos
* @param string $name
* @param string $version
- * @return array array(CompletePackageInterface, array of versions)
* @throws \InvalidArgumentException
+ * @return array array(CompletePackageInterface, array of versions)
*/
protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null)
{
@@ -291,53 +292,54 @@ EOT
*/
protected function printMeta(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo)
{
- $this->getIO()->write('name : ' . $package->getPrettyName());
- $this->getIO()->write('descrip. : ' . $package->getDescription());
- $this->getIO()->write('keywords : ' . join(', ', $package->getKeywords() ?: array()));
+ $io = $this->getIO();
+ $io->write('name : ' . $package->getPrettyName());
+ $io->write('descrip. : ' . $package->getDescription());
+ $io->write('keywords : ' . join(', ', $package->getKeywords() ?: array()));
$this->printVersions($package, $versions, $installedRepo);
- $this->getIO()->write('type : ' . $package->getType());
+ $io->write('type : ' . $package->getType());
$this->printLicenses($package);
- $this->getIO()->write('source : ' . sprintf('[%s] %s %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
- $this->getIO()->write('dist : ' . sprintf('[%s] %s %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
- $this->getIO()->write('names : ' . implode(', ', $package->getNames()));
+ $io->write('source : ' . sprintf('[%s] %s %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
+ $io->write('dist : ' . sprintf('[%s] %s %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
+ $io->write('names : ' . implode(', ', $package->getNames()));
if ($package->isAbandoned()) {
$replacement = ($package->getReplacementPackage() !== null)
? ' The author suggests using the ' . $package->getReplacementPackage(). ' package instead.'
: null;
- $this->getIO()->writeError(
+ $io->writeError(
sprintf('Attention: This package is abandoned and no longer maintained.%s', $replacement)
);
}
if ($package->getSupport()) {
- $this->getIO()->write("\nsupport");
+ $io->write("\nsupport");
foreach ($package->getSupport() as $type => $value) {
- $this->getIO()->write('' . $type . ' : '.$value);
+ $io->write('' . $type . ' : '.$value);
}
}
if ($package->getAutoload()) {
- $this->getIO()->write("\nautoload");
+ $io->write("\nautoload");
foreach ($package->getAutoload() as $type => $autoloads) {
- $this->getIO()->write('' . $type . '');
+ $io->write('' . $type . '');
if ($type === 'psr-0') {
foreach ($autoloads as $name => $path) {
- $this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
+ $io->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
}
} elseif ($type === 'psr-4') {
foreach ($autoloads as $name => $path) {
- $this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
+ $io->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
}
} elseif ($type === 'classmap') {
- $this->getIO()->write(implode(', ', $autoloads));
+ $io->write(implode(', ', $autoloads));
}
}
if ($package->getIncludePaths()) {
- $this->getIO()->write('include-path');
- $this->getIO()->write(implode(', ', $package->getIncludePaths()));
+ $io->write('include-path');
+ $io->write(implode(', ', $package->getIncludePaths()));
}
}
}
@@ -374,11 +376,12 @@ EOT
protected function printLinks(CompletePackageInterface $package, $linkType, $title = null)
{
$title = $title ?: $linkType;
+ $io = $this->getIO();
if ($links = $package->{'get'.ucfirst($linkType)}()) {
- $this->getIO()->write("\n" . $title . "");
+ $io->write("\n" . $title . "");
foreach ($links as $link) {
- $this->getIO()->write($link->getTarget() . ' ' . $link->getPrettyConstraint() . '');
+ $io->write($link->getTarget() . ' ' . $link->getPrettyConstraint() . '');
}
}
}
@@ -390,12 +393,13 @@ EOT
*/
protected function printLicenses(CompletePackageInterface $package)
{
- $spdxLicense = new SpdxLicense;
+ $spdxLicenses = new SpdxLicenses();
$licenses = $package->getLicense();
+ $io = $this->getIO();
foreach ($licenses as $licenseId) {
- $license = $spdxLicense->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url
+ $license = $spdxLicenses->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url
if (!$license) {
$out = $licenseId;
@@ -408,7 +412,7 @@ EOT
}
}
- $this->getIO()->write('license : ' . $out);
+ $io->write('license : ' . $out);
}
}
}
diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php
index 220327cb6..7455e84b8 100644
--- a/src/Composer/Command/StatusCommand.php
+++ b/src/Composer/Command/StatusCommand.php
@@ -60,6 +60,7 @@ EOT
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true);
$errors = array();
+ $io = $this->getIO();
// list packages
foreach ($installedRepo->getPackages() as $package) {
@@ -68,6 +69,10 @@ EOT
if ($downloader instanceof ChangeReportInterface) {
$targetDir = $im->getInstallPath($package);
+ if (is_link($targetDir)) {
+ $errors[$targetDir] = $targetDir . ' is a symbolic link.';
+ }
+
if ($changes = $downloader->getLocalChanges($package, $targetDir)) {
$errors[$targetDir] = $changes;
}
@@ -76,9 +81,9 @@ EOT
// output errors/warnings
if (!$errors) {
- $this->getIO()->writeError('No local changes');
+ $io->writeError('No local changes');
} else {
- $this->getIO()->writeError('You have changes in the following dependencies:');
+ $io->writeError('You have changes in the following dependencies:');
}
foreach ($errors as $path => $changes) {
@@ -86,15 +91,15 @@ EOT
$indentedChanges = implode("\n", array_map(function ($line) {
return ' ' . ltrim($line);
}, explode("\n", $changes)));
- $this->getIO()->write(''.$path.':');
- $this->getIO()->write($indentedChanges);
+ $io->write(''.$path.':');
+ $io->write($indentedChanges);
} else {
- $this->getIO()->write($path);
+ $io->write($path);
}
}
if ($errors && !$input->getOption('verbose')) {
- $this->getIO()->writeError('Use --verbose (-v) to see modified files');
+ $io->writeError('Use --verbose (-v) to see modified files');
}
// Dispatch post-status-command
diff --git a/src/Composer/Command/SuggestsCommand.php b/src/Composer/Command/SuggestsCommand.php
new file mode 100644
index 000000000..d59ef1dc6
--- /dev/null
+++ b/src/Composer/Command/SuggestsCommand.php
@@ -0,0 +1,98 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SuggestsCommand extends Command
+{
+ protected function configure()
+ {
+ $this
+ ->setName('suggests')
+ ->setDescription('Show package suggestions')
+ ->setDefinition(array(
+ new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Exclude suggestions from require-dev packages'),
+ new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that you want to list suggestions from.'),
+ ))
+ ->setHelp(<<%command.name% command shows suggested packages.
+
+With -v you also see which package suggested it and why.
+
+EOT
+ )
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $lock = $this->getComposer()->getLocker()->getLockData();
+
+ if (empty($lock)) {
+ throw new \RuntimeException('Lockfile seems to be empty?');
+ }
+
+ $packages = $lock['packages'];
+
+ if (!$input->getOption('no-dev')) {
+ $packages += $lock['packages-dev'];
+ }
+
+ $filter = $input->getArgument('packages');
+
+ foreach ($packages as $package) {
+ if (empty($package['suggest'])) {
+ continue;
+ }
+
+ if (!empty($filter) && !in_array($package['name'], $filter)) {
+ continue;
+ }
+
+ $this->printSuggestions($packages, $package['name'], $package['suggest']);
+ }
+ }
+
+ protected function printSuggestions($installed, $source, $suggestions)
+ {
+ foreach ($suggestions as $suggestion => $reason) {
+ foreach ($installed as $package) {
+ if ($package['name'] === $suggestion) {
+ continue 2;
+ }
+ }
+
+ if (empty($reason)) {
+ $reason = '*';
+ }
+
+ $this->printSuggestion($source, $suggestion, $reason);
+ }
+ }
+
+ protected function printSuggestion($package, $suggestion, $reason)
+ {
+ $io = $this->getIO();
+
+ if ($io->isVerbose()) {
+ $io->write(sprintf('%s suggests %s: %s', $package, $suggestion, $reason));
+ } else {
+ $io->write(sprintf('%s', $suggestion));
+ }
+ }
+}
diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php
index 579236143..b67ff16cf 100644
--- a/src/Composer/Command/UpdateCommand.php
+++ b/src/Composer/Command/UpdateCommand.php
@@ -47,6 +47,7 @@ class UpdateCommand extends Command
new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Add also all dependencies of whitelisted packages to the whitelist.'),
new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'),
+ new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
@@ -74,18 +75,18 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = $this->getIO();
if ($input->getOption('no-custom-installers')) {
- $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
+ $io->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.');
$input->setOption('no-plugins', true);
}
if ($input->getOption('dev')) {
- $this->getIO()->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.');
+ $io->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.');
}
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
- $io = $this->getIO();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@@ -114,7 +115,8 @@ EOT
$preferDist = $input->getOption('prefer-dist');
}
- $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
+ $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
+ $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
$install
->setDryRun($input->getOption('dry-run'))
@@ -125,6 +127,7 @@ EOT
->setDumpAutoloader(!$input->getOption('no-autoloader'))
->setRunScripts(!$input->getOption('no-scripts'))
->setOptimizeAutoloader($optimize)
+ ->setClassMapAuthoritative($authoritative)
->setUpdate(true)
->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages'))
->setWhitelistDependencies($input->getOption('with-dependencies'))
diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php
index 320032984..66902cbb2 100644
--- a/src/Composer/Command/ValidateCommand.php
+++ b/src/Composer/Command/ValidateCommand.php
@@ -12,6 +12,7 @@
namespace Composer\Command;
+use Composer\Factory;
use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Util\ConfigValidator;
use Symfony\Component\Console\Input\InputArgument;
@@ -34,14 +35,22 @@ class ValidateCommand extends Command
{
$this
->setName('validate')
- ->setDescription('Validates a composer.json')
+ ->setDescription('Validates a composer.json and composer.lock')
->setDefinition(array(
new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not make a complete validation'),
+ new InputOption('no-check-lock', null, InputOption::VALUE_NONE, 'Do not check if lock file is up to date'),
new InputOption('no-check-publish', null, InputOption::VALUE_NONE, 'Do not check for publish errors'),
- new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json')
+ new InputOption('with-dependencies', 'A', InputOption::VALUE_NONE, 'Also validate the composer.json of all installed dependencies'),
+ new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code for warnings as well as errors'),
+ new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json'),
))
->setHelp(<<getArgument('file');
+ $io = $this->getIO();
if (!file_exists($file)) {
- $this->getIO()->writeError('' . $file . ' not found.');
+ $io->writeError('' . $file . ' not found.');
- return 1;
+ return 3;
}
if (!is_readable($file)) {
- $this->getIO()->writeError('' . $file . ' is not readable.');
+ $io->writeError('' . $file . ' is not readable.');
- return 1;
+ return 3;
}
- $validator = new ConfigValidator($this->getIO());
+ $validator = new ConfigValidator($io);
$checkAll = $input->getOption('no-check-all') ? 0 : ValidatingArrayLoader::CHECK_ALL;
$checkPublish = !$input->getOption('no-check-publish');
+ $checkLock = !$input->getOption('no-check-lock');
+ $isStrict = $input->getOption('strict');
list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
- // output errors/warnings
+ $lockErrors = array();
+ $composer = Factory::create($io, $file);
+ $locker = $composer->getLocker();
+ if ($locker->isLocked() && !$locker->isFresh()) {
+ $lockErrors[] = 'The lock file is not up to date with the latest changes in composer.json.';
+ }
+
+ $this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true);
+
+ $exitCode = $errors || ($publishErrors && $checkPublish) || ($lockErrors && $checkLock) ? 2 : ($isStrict && $warnings ? 1 : 0);
+
+ if ($input->getOption('with-dependencies')) {
+ $localRepo = $composer->getRepositoryManager()->getLocalRepository();
+ foreach ($localRepo->getPackages() as $package) {
+ $path = $composer->getInstallationManager()->getInstallPath($package);
+ $file = $path . '/composer.json';
+ if (is_dir($path) && file_exists($file)) {
+ list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
+ $this->outputResult($io, $package->getPrettyName(), $errors, $warnings, $checkPublish, $publishErrors);
+
+ $depCode = $errors || ($publishErrors && $checkPublish) ? 2 : ($isStrict && $warnings ? 1 : 0);
+ $exitCode = max($depCode, $exitCode);
+ }
+ }
+ }
+
+ return $exitCode;
+ }
+
+ private function outputResult($io, $name, &$errors, &$warnings, $checkPublish = false, $publishErrors = array(), $checkLock = false, $lockErrors = array(), $printSchemaUrl = false)
+ {
if (!$errors && !$publishErrors && !$warnings) {
- $this->getIO()->write('' . $file . ' is valid');
+ $io->write('' . $name . ' is valid');
} elseif (!$errors && !$publishErrors) {
- $this->getIO()->writeError('' . $file . ' is valid, but with a few warnings');
- $this->getIO()->writeError('See https://getcomposer.org/doc/04-schema.md for details on the schema');
+ $io->writeError('' . $name . ' is valid, but with a few warnings');
+ if ($printSchemaUrl) {
+ $io->writeError('See https://getcomposer.org/doc/04-schema.md for details on the schema');
+ }
} elseif (!$errors) {
- $this->getIO()->writeError('' . $file . ' is valid for simple usage with composer but has');
- $this->getIO()->writeError('strict errors that make it unable to be published as a package:');
- $this->getIO()->writeError('See https://getcomposer.org/doc/04-schema.md for details on the schema');
+ $io->writeError('' . $name . ' is valid for simple usage with composer but has');
+ $io->writeError('strict errors that make it unable to be published as a package:');
+ if ($printSchemaUrl) {
+ $io->writeError('See https://getcomposer.org/doc/04-schema.md for details on the schema');
+ }
} else {
- $this->getIO()->writeError('' . $file . ' is invalid, the following errors/warnings were found:');
+ $io->writeError('' . $name . ' is invalid, the following errors/warnings were found:');
+ }
+
+ // If checking publish errors, display them as errors, otherwise just show them as warnings
+ if ($checkPublish) {
+ $errors = array_merge($errors, $publishErrors);
+ } else {
+ $warnings = array_merge($warnings, $publishErrors);
+ }
+
+ // If checking lock errors, display them as errors, otherwise just show them as warnings
+ if ($checkLock) {
+ $errors = array_merge($errors, $lockErrors);
+ } else {
+ $warnings = array_merge($warnings, $lockErrors);
}
$messages = array(
@@ -92,19 +152,10 @@ EOT
'warning' => $warnings,
);
- // If checking publish errors, display them errors, otherwise just show them as warnings
- if ($checkPublish) {
- $messages['error'] = array_merge($messages['error'], $publishErrors);
- } else {
- $messages['warning'] = array_merge($messages['warning'], $publishErrors);
- }
-
foreach ($messages as $style => $msgs) {
foreach ($msgs as $msg) {
- $this->getIO()->writeError('<' . $style . '>' . $msg . '' . $style . '>');
+ $io->writeError('<' . $style . '>' . $msg . '' . $style . '>');
}
}
-
- return $errors || ($publishErrors && $checkPublish) ? 1 : 0;
}
}
diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php
index 749adf659..de977e8e2 100644
--- a/src/Composer/Compiler.php
+++ b/src/Composer/Compiler.php
@@ -13,6 +13,7 @@
namespace Composer;
use Composer\Json\JsonFile;
+use Composer\Spdx\SpdxLicenses;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process;
use Seld\PharUtils\Timestamps;
@@ -32,8 +33,8 @@ class Compiler
/**
* Compiles composer into a single phar file
*
- * @throws \RuntimeException
* @param string $pharFile The full path to the file to create
+ * @throws \RuntimeException
*/
public function compile($pharFile = 'composer.phar')
{
@@ -95,7 +96,8 @@ class Compiler
$finder = new Finder();
$finder->files()
->name('*.json')
- ->in(__DIR__ . '/../../res')
+ ->in(__DIR__.'/../../res')
+ ->in(SpdxLicenses::getResourcesDir())
->sort($finderSort)
;
@@ -116,6 +118,8 @@ class Compiler
->in(__DIR__.'/../../vendor/seld/jsonlint/')
->in(__DIR__.'/../../vendor/seld/cli-prompt/')
->in(__DIR__.'/../../vendor/justinrainbow/json-schema/')
+ ->in(__DIR__.'/../../vendor/composer/spdx-licenses/')
+ ->in(__DIR__.'/../../vendor/composer/semver/')
->sort($finderSort)
;
diff --git a/src/Composer/Config.php b/src/Composer/Config.php
index 87f8f03ff..4c3669db9 100644
--- a/src/Composer/Config.php
+++ b/src/Composer/Config.php
@@ -13,7 +13,6 @@
namespace Composer;
use Composer\Config\ConfigSourceInterface;
-use Composer\Plugin\PluginInterface;
/**
* @author Jordi Boggiano
@@ -59,7 +58,7 @@ class Config
'type' => 'composer',
'url' => 'https?://packagist.org',
'allow_ssl_downgrade' => true,
- )
+ ),
);
private $config;
@@ -70,7 +69,7 @@ class Config
private $useEnvironment;
/**
- * @param boolean $useEnvironment Use COMPOSER_ environment variables to replace config settings
+ * @param bool $useEnvironment Use COMPOSER_ environment variables to replace config settings
*/
public function __construct($useEnvironment = true, $baseDir = null)
{
@@ -183,7 +182,7 @@ class Config
return $val;
}
- return ($flags & self::RELATIVE_PATHS == 1) ? $val : $this->realpath($val);
+ return ($flags & self::RELATIVE_PATHS == self::RELATIVE_PATHS) ? $val : $this->realpath($val);
case 'cache-ttl':
return (int) $this->config[$key];
@@ -334,8 +333,8 @@ class Config
* This should be used to read COMPOSER_ environment variables
* that overload config values.
*
- * @param string $var
- * @return string|boolean
+ * @param string $var
+ * @return string|bool
*/
private function getComposerEnv($var)
{
diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php
index ee4f4e9c0..21bc22937 100644
--- a/src/Composer/Console/Application.php
+++ b/src/Composer/Console/Application.php
@@ -89,9 +89,10 @@ class Application extends BaseApplication
{
$this->io = new ConsoleIO($input, $output, $this->getHelperSet());
ErrorHandler::register($this->io);
+ $io = $this->getIO();
if (PHP_VERSION_ID < 50302) {
- $this->getIO()->writeError('Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.');
+ $io->writeError('Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.');
}
if (defined('COMPOSER_DEV_WARNING_TIME')) {
@@ -104,7 +105,7 @@ class Application extends BaseApplication
}
if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
if (time() > COMPOSER_DEV_WARNING_TIME) {
- $this->getIO()->writeError(sprintf('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.', $_SERVER['PHP_SELF']));
+ $io->writeError(sprintf('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.', $_SERVER['PHP_SELF']));
}
}
}
@@ -117,8 +118,8 @@ class Application extends BaseApplication
if ($newWorkDir = $this->getNewWorkingDir($input)) {
$oldWorkingDir = getcwd();
chdir($newWorkDir);
- if ($this->getIO()->isDebug() >= 4) {
- $this->getIO()->writeError('Changed CWD to ' . getcwd());
+ if ($io->isDebug() >= 4) {
+ $io->writeError('Changed CWD to ' . getcwd());
}
}
@@ -129,7 +130,7 @@ class Application extends BaseApplication
foreach ($composer['scripts'] as $script => $dummy) {
if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
if ($this->has($script)) {
- $this->getIO()->writeError('A script named '.$script.' would override a native Composer function and has been skipped');
+ $io->writeError('A script named '.$script.' would override a native Composer function and has been skipped');
} else {
$this->add(new Command\ScriptAliasCommand($script));
}
@@ -150,7 +151,7 @@ class Application extends BaseApplication
}
if (isset($startTime)) {
- $this->getIO()->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s');
+ $io->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s');
}
return $result;
@@ -158,8 +159,8 @@ class Application extends BaseApplication
/**
* @param InputInterface $input
- * @return string
* @throws \RuntimeException
+ * @return string
*/
private function getNewWorkingDir(InputInterface $input)
{
@@ -176,30 +177,32 @@ class Application extends BaseApplication
*/
public function renderException($exception, $output)
{
+ $io = $this->getIO();
+
try {
$composer = $this->getComposer(false, true);
if ($composer) {
$config = $composer->getConfig();
- $minSpaceFree = 1024*1024;
+ $minSpaceFree = 1024 * 1024;
if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
|| (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
|| (($df = @disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
) {
- $this->getIO()->writeError('The disk hosting '.$dir.' is full, this may be the cause of the following exception');
+ $io->writeError('The disk hosting '.$dir.' is full, this may be the cause of the following exception');
}
}
} catch (\Exception $e) {
}
if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
- $this->getIO()->writeError('The following exception may be caused by a stale entry in your cmd.exe AutoRun');
- $this->getIO()->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details');
+ $io->writeError('The following exception may be caused by a stale entry in your cmd.exe AutoRun');
+ $io->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details');
}
if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
- $this->getIO()->writeError('The following exception is caused by a lack of memory and not having swap configured');
- $this->getIO()->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details');
+ $io->writeError('The following exception is caused by a lack of memory and not having swap configured');
+ $io->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details');
}
if ($output instanceof ConsoleOutputInterface) {
@@ -272,6 +275,7 @@ class Application extends BaseApplication
$commands[] = new Command\SearchCommand();
$commands[] = new Command\ValidateCommand();
$commands[] = new Command\ShowCommand();
+ $commands[] = new Command\SuggestsCommand();
$commands[] = new Command\RequireCommand();
$commands[] = new Command\DumpAutoloadCommand();
$commands[] = new Command\StatusCommand();
diff --git a/src/Composer/Console/HtmlOutputFormatter.php b/src/Composer/Console/HtmlOutputFormatter.php
index cb42133c3..994fcbcd5 100644
--- a/src/Composer/Console/HtmlOutputFormatter.php
+++ b/src/Composer/Console/HtmlOutputFormatter.php
@@ -27,7 +27,7 @@ class HtmlOutputFormatter extends OutputFormatter
34 => 'blue',
35 => 'magenta',
36 => 'cyan',
- 37 => 'white'
+ 37 => 'white',
);
private static $availableBackgroundColors = array(
40 => 'black',
@@ -37,7 +37,7 @@ class HtmlOutputFormatter extends OutputFormatter
44 => 'blue',
45 => 'magenta',
46 => 'cyan',
- 47 => 'white'
+ 47 => 'white',
);
private static $availableOptions = array(
1 => 'bold',
@@ -60,6 +60,7 @@ class HtmlOutputFormatter extends OutputFormatter
$formatted = parent::format($message);
$clearEscapeCodes = '(?:39|49|0|22|24|25|27|28)';
+
return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[(?:".$clearEscapeCodes.";)*?".$clearEscapeCodes."m}s", array($this, 'formatHtml'), $formatted);
}
diff --git a/src/Composer/DependencyResolver/DefaultPolicy.php b/src/Composer/DependencyResolver/DefaultPolicy.php
index 440d6856c..684f11851 100644
--- a/src/Composer/DependencyResolver/DefaultPolicy.php
+++ b/src/Composer/DependencyResolver/DefaultPolicy.php
@@ -15,7 +15,7 @@ namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
/**
* @author Nils Adermann
@@ -38,8 +38,8 @@ class DefaultPolicy implements PolicyInterface
return BasePackage::$stabilities[$stabA] < BasePackage::$stabilities[$stabB];
}
- $constraint = new VersionConstraint($operator, $b->getVersion());
- $version = new VersionConstraint('==', $a->getVersion());
+ $constraint = new Constraint($operator, $b->getVersion());
+ $version = new Constraint('==', $a->getVersion());
return $constraint->matchSpecific($version, true);
}
@@ -194,7 +194,7 @@ class DefaultPolicy implements PolicyInterface
foreach ($source->getReplaces() as $link) {
if ($link->getTarget() === $target->getName()
// && (null === $link->getConstraint() ||
-// $link->getConstraint()->matches(new VersionConstraint('==', $target->getVersion())))) {
+// $link->getConstraint()->matches(new Constraint('==', $target->getVersion())))) {
) {
return true;
}
diff --git a/src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php b/src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php
index c901bd190..920e54e67 100644
--- a/src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php
+++ b/src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php
@@ -13,6 +13,7 @@
namespace Composer\DependencyResolver\Operation;
use Composer\Package\AliasPackage;
+use Composer\Package\PackageInterface;
/**
* Solver install operation.
diff --git a/src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php b/src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php
index 56f7ac19b..77f3aef8c 100644
--- a/src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php
+++ b/src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php
@@ -13,6 +13,7 @@
namespace Composer\DependencyResolver\Operation;
use Composer\Package\AliasPackage;
+use Composer\Package\PackageInterface;
/**
* Solver install operation.
diff --git a/src/Composer/DependencyResolver/Operation/SolverOperation.php b/src/Composer/DependencyResolver/Operation/SolverOperation.php
index a4e8384d3..e1a68585e 100644
--- a/src/Composer/DependencyResolver/Operation/SolverOperation.php
+++ b/src/Composer/DependencyResolver/Operation/SolverOperation.php
@@ -12,7 +12,6 @@
namespace Composer\DependencyResolver\Operation;
-use Composer\Package\Version\VersionParser;
use Composer\Package\PackageInterface;
/**
@@ -46,6 +45,6 @@ abstract class SolverOperation implements OperationInterface
protected function formatVersion(PackageInterface $package)
{
- return VersionParser::formatVersion($package);
+ return $package->getFullPrettyVersion();
}
}
diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php
index 000d63805..96e46c531 100644
--- a/src/Composer/DependencyResolver/Pool.php
+++ b/src/Composer/DependencyResolver/Pool.php
@@ -14,10 +14,10 @@ namespace Composer\DependencyResolver;
use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
-use Composer\Package\Version\VersionParser;
-use Composer\Package\LinkConstraint\LinkConstraintInterface;
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Package\LinkConstraint\EmptyConstraint;
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\ConstraintInterface;
+use Composer\Semver\Constraint\Constraint;
+use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\CompositeRepository;
use Composer\Repository\ComposerRepository;
@@ -31,7 +31,7 @@ use Composer\Package\PackageInterface;
* @author Nils Adermann
* @author Jordi Boggiano
*/
-class Pool
+class Pool implements \Countable
{
const MATCH_NAME = -1;
const MATCH_NONE = 0;
@@ -150,27 +150,35 @@ class Pool
}
/**
- * Retrieves the package object for a given package id.
- *
- * @param int $id
- * @return PackageInterface
- */
+ * Retrieves the package object for a given package id.
+ *
+ * @param int $id
+ * @return PackageInterface
+ */
public function packageById($id)
{
return $this->packages[$id - 1];
}
+ /**
+ * Returns how many packages have been loaded into the pool
+ */
+ public function count()
+ {
+ return count($this->packages);
+ }
+
/**
* Searches all packages providing the given package name and match the constraint
*
- * @param string $name The package name to be searched for
- * @param LinkConstraintInterface $constraint A constraint that all returned
- * packages must match or null to return all
- * @param bool $mustMatchName Whether the name of returned packages
- * must match the given name
- * @return PackageInterface[] A set of packages
+ * @param string $name The package name to be searched for
+ * @param ConstraintInterface $constraint A constraint that all returned
+ * packages must match or null to return all
+ * @param bool $mustMatchName Whether the name of returned packages
+ * must match the given name
+ * @return PackageInterface[] A set of packages
*/
- public function whatProvides($name, LinkConstraintInterface $constraint = null, $mustMatchName = false)
+ public function whatProvides($name, ConstraintInterface $constraint = null, $mustMatchName = false)
{
$key = ((int) $mustMatchName).$constraint;
if (isset($this->providerCache[$name][$key])) {
@@ -309,12 +317,12 @@ class Pool
* Checks if the package matches the given constraint directly or through
* provided or replaced packages
*
- * @param array|PackageInterface $candidate
- * @param string $name Name of the package to be matched
- * @param LinkConstraintInterface $constraint The constraint to verify
- * @return int One of the MATCH* constants of this class or 0 if there is no match
+ * @param array|PackageInterface $candidate
+ * @param string $name Name of the package to be matched
+ * @param ConstraintInterface $constraint The constraint to verify
+ * @return int One of the MATCH* constants of this class or 0 if there is no match
*/
- private function match($candidate, $name, LinkConstraintInterface $constraint = null)
+ private function match($candidate, $name, ConstraintInterface $constraint = null)
{
$candidateName = $candidate->getName();
$candidateVersion = $candidate->getVersion();
@@ -328,7 +336,7 @@ class Pool
}
if ($candidateName === $name) {
- $pkgConstraint = new VersionConstraint('==', $candidateVersion);
+ $pkgConstraint = new Constraint('==', $candidateVersion);
if ($constraint === null || $constraint->matches($pkgConstraint)) {
return $requireFilter->matches($pkgConstraint) ? self::MATCH : self::MATCH_FILTERED;
diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php
index a1910c3ed..f4e5f1744 100644
--- a/src/Composer/DependencyResolver/Problem.php
+++ b/src/Composer/DependencyResolver/Problem.php
@@ -47,7 +47,7 @@ class Problem
*/
public function addRule(Rule $rule)
{
- $this->addReason($rule->getId(), array(
+ $this->addReason(spl_object_hash($rule), array(
'rule' => $rule,
'job' => $rule->getJob(),
));
@@ -87,8 +87,12 @@ class Problem
}
if ($job && $job['cmd'] === 'install' && empty($packages)) {
+
// handle php/hhvm
if ($job['packageName'] === 'php' || $job['packageName'] === 'php-64bit' || $job['packageName'] === 'hhvm') {
+ $available = $this->pool->whatProvides($job['packageName']);
+ $version = count($available) ? $available[0]->getPrettyVersion() : phpversion();
+
$msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but ';
if (defined('HHVM_VERSION')) {
@@ -97,7 +101,7 @@ class Problem
return $msg . 'you are running this with PHP and not HHVM.';
}
- return $msg . 'your PHP version ('. phpversion().') does not satisfy that requirement.';
+ return $msg . 'your PHP version ('. $version .') does not satisfy that requirement.';
}
// handle php extensions
@@ -218,7 +222,7 @@ class Problem
/**
* Turns a constraint into text usable in a sentence describing a job
*
- * @param \Composer\Package\LinkConstraint\LinkConstraintInterface $constraint
+ * @param \Composer\Semver\Constraint\ConstraintInterface $constraint
* @return string
*/
protected function constraintToText($constraint)
diff --git a/src/Composer/DependencyResolver/Request.php b/src/Composer/DependencyResolver/Request.php
index 0776f040e..7eacdf1f6 100644
--- a/src/Composer/DependencyResolver/Request.php
+++ b/src/Composer/DependencyResolver/Request.php
@@ -12,7 +12,7 @@
namespace Composer\DependencyResolver;
-use Composer\Package\LinkConstraint\LinkConstraintInterface;
+use Composer\Semver\Constraint\ConstraintInterface;
/**
* @author Nils Adermann
@@ -26,17 +26,17 @@ class Request
$this->jobs = array();
}
- public function install($packageName, LinkConstraintInterface $constraint = null)
+ public function install($packageName, ConstraintInterface $constraint = null)
{
$this->addJob($packageName, 'install', $constraint);
}
- public function update($packageName, LinkConstraintInterface $constraint = null)
+ public function update($packageName, ConstraintInterface $constraint = null)
{
$this->addJob($packageName, 'update', $constraint);
}
- public function remove($packageName, LinkConstraintInterface $constraint = null)
+ public function remove($packageName, ConstraintInterface $constraint = null)
{
$this->addJob($packageName, 'remove', $constraint);
}
@@ -46,12 +46,12 @@ class Request
*
* These jobs will not be tempered with by the solver
*/
- public function fix($packageName, LinkConstraintInterface $constraint = null)
+ public function fix($packageName, ConstraintInterface $constraint = null)
{
$this->addJob($packageName, 'install', $constraint, true);
}
- protected function addJob($packageName, $cmd, LinkConstraintInterface $constraint = null, $fixed = false)
+ protected function addJob($packageName, $cmd, ConstraintInterface $constraint = null, $fixed = false)
{
$packageName = strtolower($packageName);
@@ -59,7 +59,7 @@ class Request
'cmd' => $cmd,
'packageName' => $packageName,
'constraint' => $constraint,
- 'fixed' => $fixed
+ 'fixed' => $fixed,
);
}
diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php
index 37db43745..03de5ab84 100644
--- a/src/Composer/DependencyResolver/Rule.php
+++ b/src/Composer/DependencyResolver/Rule.php
@@ -29,63 +29,51 @@ class Rule
const RULE_LEARNED = 12;
const RULE_PACKAGE_ALIAS = 13;
+ const BITFIELD_TYPE = 0;
+ const BITFIELD_REASON = 8;
+ const BITFIELD_DISABLED = 16;
+
/**
* READ-ONLY: The literals this rule consists of.
* @var array
*/
public $literals;
- protected $disabled;
- protected $type;
- protected $id;
- protected $reason;
+ protected $bitfield;
protected $reasonData;
- protected $job;
-
- protected $ruleHash;
-
public function __construct(array $literals, $reason, $reasonData, $job = null)
{
// sort all packages ascending by id
sort($literals);
$this->literals = $literals;
- $this->reason = $reason;
$this->reasonData = $reasonData;
- $this->disabled = false;
+ if ($job) {
+ $this->job = $job;
+ }
- $this->job = $job;
-
- $this->type = -1;
-
- $this->ruleHash = substr(md5(implode(',', $this->literals)), 0, 5);
+ $this->bitfield = (0 << self::BITFIELD_DISABLED) |
+ ($reason << self::BITFIELD_REASON) |
+ (255 << self::BITFIELD_TYPE);
}
public function getHash()
{
- return $this->ruleHash;
- }
+ $data = unpack('ihash', md5(implode(',', $this->literals), true));
- public function setId($id)
- {
- $this->id = $id;
- }
-
- public function getId()
- {
- return $this->id;
+ return $data['hash'];
}
public function getJob()
{
- return $this->job;
+ return isset($this->job) ? $this->job : null;
}
public function getReason()
{
- return $this->reason;
+ return ($this->bitfield & (255 << self::BITFIELD_REASON)) >> self::BITFIELD_REASON;
}
public function getReasonData()
@@ -95,11 +83,11 @@ class Rule
public function getRequiredPackage()
{
- if ($this->reason === self::RULE_JOB_INSTALL) {
+ if ($this->getReason() === self::RULE_JOB_INSTALL) {
return $this->reasonData;
}
- if ($this->reason === self::RULE_PACKAGE_REQUIRES) {
+ if ($this->getReason() === self::RULE_PACKAGE_REQUIRES) {
return $this->reasonData->getTarget();
}
}
@@ -114,10 +102,6 @@ class Rule
*/
public function equals(Rule $rule)
{
- if ($this->ruleHash !== $rule->ruleHash) {
- return false;
- }
-
if (count($this->literals) != count($rule->literals)) {
return false;
}
@@ -133,32 +117,32 @@ class Rule
public function setType($type)
{
- $this->type = $type;
+ $this->bitfield = ($this->bitfield & ~(255 << self::BITFIELD_TYPE)) | ((255 & $type) << self::BITFIELD_TYPE);
}
public function getType()
{
- return $this->type;
+ return ($this->bitfield & (255 << self::BITFIELD_TYPE)) >> self::BITFIELD_TYPE;
}
public function disable()
{
- $this->disabled = true;
+ $this->bitfield = ($this->bitfield & ~(255 << self::BITFIELD_DISABLED)) | (1 << self::BITFIELD_DISABLED);
}
public function enable()
{
- $this->disabled = false;
+ $this->bitfield = $this->bitfield & ~(255 << self::BITFIELD_DISABLED);
}
public function isDisabled()
{
- return $this->disabled;
+ return (bool) (($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED);
}
public function isEnabled()
{
- return !$this->disabled;
+ return !(($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED);
}
/**
@@ -184,7 +168,7 @@ class Rule
$ruleText .= $pool->literalToPrettyString($literal, $installedMap);
}
- switch ($this->reason) {
+ switch ($this->getReason()) {
case self::RULE_INTERNAL_ALLOW_UPDATE:
return $ruleText;
@@ -216,16 +200,17 @@ class Rule
} else {
$targetName = $this->reasonData->getTarget();
- // handle php extensions
if ($targetName === 'php' || $targetName === 'php-64bit' || $targetName === 'hhvm') {
+ // handle php/hhvm
if (defined('HHVM_VERSION')) {
$text .= ' -> your HHVM version does not satisfy that requirement.';
} elseif ($targetName === 'hhvm') {
$text .= ' -> you are running this with PHP and not HHVM.';
} else {
- $text .= ' -> your PHP version ('. phpversion().') does not satisfy that requirement.';
+ $text .= ' -> your PHP version ('. phpversion() .') or "config.platform.php" value does not satisfy that requirement.';
}
} elseif (0 === strpos($targetName, 'ext-')) {
+ // handle php extensions
$ext = substr($targetName, 4);
$error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
diff --git a/src/Composer/DependencyResolver/RuleSet.php b/src/Composer/DependencyResolver/RuleSet.php
index b9545123f..26771cef6 100644
--- a/src/Composer/DependencyResolver/RuleSet.php
+++ b/src/Composer/DependencyResolver/RuleSet.php
@@ -30,7 +30,7 @@ class RuleSet implements \IteratorAggregate, \Countable
public $ruleById;
protected static $types = array(
- -1 => 'UNKNOWN',
+ 255 => 'UNKNOWN',
self::TYPE_PACKAGE => 'PACKAGE',
self::TYPE_JOB => 'JOB',
self::TYPE_LEARNED => 'LEARNED',
@@ -66,7 +66,6 @@ class RuleSet implements \IteratorAggregate, \Countable
$this->ruleById[$this->nextRuleId] = $rule;
$rule->setType($type);
- $rule->setId($this->nextRuleId);
$this->nextRuleId++;
$hash = $rule->getHash();
@@ -131,7 +130,7 @@ class RuleSet implements \IteratorAggregate, \Countable
public function getTypes()
{
$types = self::$types;
- unset($types[-1]);
+ unset($types[255]);
return array_keys($types);
}
diff --git a/src/Composer/DependencyResolver/RuleWatchNode.php b/src/Composer/DependencyResolver/RuleWatchNode.php
index cdbf6a00b..907cb4cc0 100644
--- a/src/Composer/DependencyResolver/RuleWatchNode.php
+++ b/src/Composer/DependencyResolver/RuleWatchNode.php
@@ -83,7 +83,7 @@ class RuleWatchNode
/**
* Given one watched literal, this method returns the other watched literal
*
- * @param int The watched literal that should not be returned
+ * @param int $literal The watched literal that should not be returned
* @return int A literal
*/
public function getOtherWatch($literal)
diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php
index 6975df2cd..0568a4d2c 100644
--- a/src/Composer/DependencyResolver/Solver.php
+++ b/src/Composer/DependencyResolver/Solver.php
@@ -50,6 +50,11 @@ class Solver
$this->ruleSetGenerator = new RuleSetGenerator($policy, $pool);
}
+ public function getRuleSetSize()
+ {
+ return count($this->rules);
+ }
+
// aka solver_makeruledecisions
private function makeAssertionRuleDecisions()
{
@@ -212,7 +217,7 @@ class Solver
* Evaluates each term affected by the decision (linked through watches)
* If we find unit rules we make new decisions based on them
*
- * @param integer $level
+ * @param int $level
* @return Rule|null A rule on conflict, otherwise null.
*/
protected function propagate($level)
@@ -314,7 +319,7 @@ class Solver
$this->rules->add($newRule, RuleSet::TYPE_LEARNED);
- $this->learnedWhy[$newRule->getId()] = $why;
+ $this->learnedWhy[spl_object_hash($newRule)] = $why;
$ruleNode = new RuleWatchNode($newRule);
$ruleNode->watch2OnHighest($this->decisions);
@@ -449,7 +454,7 @@ class Solver
private function analyzeUnsolvableRule($problem, $conflictRule)
{
- $why = $conflictRule->getId();
+ $why = spl_object_hash($conflictRule);
if ($conflictRule->getType() == RuleSet::TYPE_LEARNED) {
$learnedWhy = $this->learnedWhy[$why];
@@ -567,7 +572,7 @@ class Solver
private function enableDisableLearnedRules()
{
foreach ($this->rules->getIteratorFor(RuleSet::TYPE_LEARNED) as $rule) {
- $why = $this->learnedWhy[$rule->getId()];
+ $why = $this->learnedWhy[spl_object_hash($rule)];
$problemRules = $this->learnedPool[$why];
$foundDisabled = false;
diff --git a/src/Composer/DependencyResolver/SolverProblemsException.php b/src/Composer/DependencyResolver/SolverProblemsException.php
index 308172bcc..9973f9d39 100644
--- a/src/Composer/DependencyResolver/SolverProblemsException.php
+++ b/src/Composer/DependencyResolver/SolverProblemsException.php
@@ -32,7 +32,7 @@ class SolverProblemsException extends \RuntimeException
{
$text = "\n";
foreach ($this->problems as $i => $problem) {
- $text .= " Problem ".($i+1).$problem->getPrettyString($this->installedMap)."\n";
+ $text .= " Problem ".($i + 1).$problem->getPrettyString($this->installedMap)."\n";
}
if (strpos($text, 'could not be found') || strpos($text, 'no matching package found')) {
diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php
index ff0b9e338..f42b82872 100644
--- a/src/Composer/Downloader/ArchiveDownloader.php
+++ b/src/Composer/Downloader/ArchiveDownloader.php
@@ -77,7 +77,11 @@ abstract class ArchiveDownloader extends FileDownloader
// retry downloading if we have an invalid zip file
if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) {
- $this->io->writeError(' Invalid zip file, retrying...');
+ if ($this->io->isDebug()) {
+ $this->io->writeError(' Invalid zip file ('.$e->getMessage().'), retrying...');
+ } else {
+ $this->io->writeError(' Invalid zip file, retrying...');
+ }
usleep(500000);
continue;
}
@@ -115,7 +119,7 @@ abstract class ArchiveDownloader extends FileDownloader
// update api archives to the proper reference
$url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference();
}
- } else if ($package->getDistReference() && strpos($url, 'bitbucket.org')) {
+ } elseif ($package->getDistReference() && strpos($url, 'bitbucket.org')) {
if (preg_match('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) {
// update Bitbucket archives to the proper reference
$url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $package->getDistReference() . '.' . $match[4];
diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php
index 5c0980725..4d2e9c8f4 100644
--- a/src/Composer/Downloader/DownloadManager.php
+++ b/src/Composer/Downloader/DownloadManager.php
@@ -103,10 +103,9 @@ class DownloadManager
/**
* Returns downloader for a specific installation type.
*
- * @param string $type installation type
- * @return DownloaderInterface
- *
+ * @param string $type installation type
* @throws \InvalidArgumentException if downloader for provided type is not registered
+ * @return DownloaderInterface
*/
public function getDownloader($type)
{
@@ -121,12 +120,11 @@ class DownloadManager
/**
* Returns downloader for already installed package.
*
- * @param PackageInterface $package package instance
- * @return DownloaderInterface|null
- *
+ * @param PackageInterface $package package instance
* @throws \InvalidArgumentException if package has no installation source specified
* @throws \LogicException if specific downloader used to load package with
- * wrong type
+ * wrong type
+ * @return DownloaderInterface|null
*/
public function getDownloaderForInstalledPackage(PackageInterface $package)
{
diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php
index 04f8fc4b5..77a08cbf4 100644
--- a/src/Composer/Downloader/FileDownloader.php
+++ b/src/Composer/Downloader/FileDownloader.php
@@ -16,7 +16,6 @@ use Composer\Config;
use Composer\Cache;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
-use Composer\Package\Version\VersionParser;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\EventDispatcher\EventDispatcher;
@@ -81,7 +80,7 @@ class FileDownloader implements DownloaderInterface
throw new \InvalidArgumentException('The given package is missing url information');
}
- $this->io->writeError(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")");
+ $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
$urls = $package->getDistUrls();
while ($url = array_shift($urls)) {
@@ -138,7 +137,7 @@ class FileDownloader implements DownloaderInterface
break;
} catch (TransportException $e) {
// 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) {
throw $e;
}
if ($this->io->isVerbose()) {
@@ -205,7 +204,7 @@ class FileDownloader implements DownloaderInterface
*/
public function remove(PackageInterface $package, $path)
{
- $this->io->writeError(" - Removing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")");
+ $this->io->writeError(" - Removing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
if (!$this->filesystem->removeDirectory($path)) {
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
}
@@ -226,11 +225,10 @@ class FileDownloader implements DownloaderInterface
/**
* Process the download url
*
- * @param PackageInterface $package package the url is coming from
- * @param string $url download url
- * @return string url
- *
+ * @param PackageInterface $package package the url is coming from
+ * @param string $url download url
* @throws \RuntimeException If any problem with the url
+ * @return string url
*/
protected function processUrl(PackageInterface $package, $url)
{
diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php
index a869e5b5a..60a896256 100644
--- a/src/Composer/Downloader/GitDownloader.php
+++ b/src/Composer/Downloader/GitDownloader.php
@@ -13,7 +13,6 @@
namespace Composer\Downloader;
use Composer\Package\PackageInterface;
-use Composer\Util\GitHub;
use Composer\Util\Git as GitUtil;
use Composer\Util\ProcessExecutor;
use Composer\IO\IOInterface;
@@ -82,7 +81,7 @@ class GitDownloader extends VcsDownloader
$command = 'git remote set-url composer %s && git fetch composer && git fetch --tags composer';
$commandCallable = function ($url) use ($command) {
- return sprintf($command, ProcessExecutor::escape ($url));
+ return sprintf($command, ProcessExecutor::escape($url));
};
$this->gitUtil->runCommand($commandCallable, $url, $path);
@@ -150,7 +149,7 @@ class GitDownloader extends VcsDownloader
}
while (true) {
- switch ($this->io->ask(' Discard changes [y,n,v,'.($update ? 's,' : '').'?]? ', '?')) {
+ switch ($this->io->ask(' Discard changes [y,n,v,d,'.($update ? 's,' : '').'?]? ', '?')) {
case 'y':
$this->discardChanges($path);
break 2;
@@ -170,6 +169,10 @@ class GitDownloader extends VcsDownloader
$this->io->writeError($changes);
break;
+ case 'd':
+ $this->viewDiff($path);
+ break;
+
case '?':
default:
help:
@@ -177,6 +180,7 @@ class GitDownloader extends VcsDownloader
' y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
' n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
' v - view modified files',
+ ' d - view local modifications (diff)',
));
if ($update) {
$this->io->writeError(' s - stash changes and try to reapply them after the update');
@@ -205,13 +209,12 @@ class GitDownloader extends VcsDownloader
/**
* Updates the given path to the given commit ref
*
- * @param string $path
- * @param string $reference
- * @param string $branch
- * @param \DateTime $date
- * @return null|string if a string is returned, it is the commit reference that was checked out if the original could not be found
- *
+ * @param string $path
+ * @param string $reference
+ * @param string $branch
+ * @param \DateTime $date
* @throws \RuntimeException
+ * @return null|string if a string is returned, it is the commit reference that was checked out if the original could not be found
*/
protected function updateToCommit($path, $reference, $branch, $date)
{
@@ -327,6 +330,20 @@ class GitDownloader extends VcsDownloader
$this->hasStashedChanges = true;
}
+ /**
+ * @param $path
+ * @throws \RuntimeException
+ */
+ protected function viewDiff($path)
+ {
+ $path = $this->normalizePath($path);
+ if (0 !== $this->process->execute('git diff HEAD', $output, $path)) {
+ throw new \RuntimeException("Could not view diff\n\n:".$this->process->getErrorOutput());
+ }
+
+ $this->io->writeError($output);
+ }
+
protected function normalizePath($path)
{
if (defined('PHP_WINDOWS_VERSION_MAJOR') && strlen($path) > 0) {
diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php
new file mode 100644
index 000000000..3ff47da8e
--- /dev/null
+++ b/src/Composer/Downloader/PathDownloader.php
@@ -0,0 +1,61 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Downloader;
+
+use Composer\Package\PackageInterface;
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Filesystem\Filesystem;
+
+/**
+ * Download a package from a local path.
+ *
+ * @author Samuel Roze
+ * @author Johann Reinke
+ */
+class PathDownloader extends FileDownloader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function download(PackageInterface $package, $path)
+ {
+ $fileSystem = new Filesystem();
+ $this->filesystem->removeDirectory($path);
+
+ $this->io->writeError(sprintf(
+ ' - Installing %s (%s)',
+ $package->getName(),
+ $package->getFullPrettyVersion()
+ ));
+
+ $url = $package->getDistUrl();
+ $realUrl = realpath($url);
+ if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) {
+ throw new \RuntimeException(sprintf(
+ 'Path "%s" is not found',
+ $url
+ ));
+ }
+
+ try {
+ $shortestPath = $this->filesystem->findShortestPath($path, $realUrl);
+ $fileSystem->symlink($shortestPath, $path);
+ $this->io->writeError(sprintf(' Symlinked from %s', $url));
+ } catch (IOException $e) {
+ $fileSystem->mirror($realUrl, $path);
+ $this->io->writeError(sprintf(' Mirrored from %s', $url));
+ }
+
+ $this->io->writeError('');
+ }
+}
diff --git a/src/Composer/Downloader/PearPackageExtractor.php b/src/Composer/Downloader/PearPackageExtractor.php
index 1106d927f..44267d558 100644
--- a/src/Composer/Downloader/PearPackageExtractor.php
+++ b/src/Composer/Downloader/PearPackageExtractor.php
@@ -48,7 +48,6 @@ class PearPackageExtractor
* @param array $vars used for replacement tasks
* @throws \RuntimeException
* @throws \UnexpectedValueException
- *
*/
public function extractTo($target, array $roles = array('php' => '/', 'script' => '/bin'), $vars = array())
{
@@ -130,9 +129,9 @@ class PearPackageExtractor
* @param string $source string path to extracted files
* @param array $roles array [role => roleRoot] relative root for files having that role
* @param array $vars list of values can be used for replacement tasks
+ * @throws \RuntimeException
* @return array array of 'source' => 'target', where source is location of file in the tarball (relative to source
* path, and target is destination of file (also relative to $source path)
- * @throws \RuntimeException
*/
private function buildCopyActions($source, array $roles, $vars)
{
diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php
index ae2769999..d99fc7997 100644
--- a/src/Composer/Downloader/PerforceDownloader.php
+++ b/src/Composer/Downloader/PerforceDownloader.php
@@ -43,7 +43,7 @@ class PerforceDownloader extends VcsDownloader
private function getLabelFromSourceReference($ref)
{
- $pos = strpos($ref,'@');
+ $pos = strpos($ref, '@');
if (false !== $pos) {
return substr($ref, $pos + 1);
}
diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php
index a13d2310f..addf95d37 100644
--- a/src/Composer/Downloader/SvnDownloader.php
+++ b/src/Composer/Downloader/SvnDownloader.php
@@ -151,7 +151,7 @@ class SvnDownloader extends VcsDownloader
*/
protected function getCommitLogs($fromReference, $toReference, $path)
{
- if (preg_match('{.*@(\d+)$}', $fromReference) && preg_match('{.*@(\d+)$}', $toReference) ) {
+ if (preg_match('{.*@(\d+)$}', $fromReference) && preg_match('{.*@(\d+)$}', $toReference)) {
// strip paths from references and only keep the actual revision
$fromRevision = preg_replace('{.*@(\d+)$}', '$1', $fromReference);
$toRevision = preg_replace('{.*@(\d+)$}', '$1', $toReference);
diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php
index 254f6143d..c77dd439b 100644
--- a/src/Composer/Downloader/VcsDownloader.php
+++ b/src/Composer/Downloader/VcsDownloader.php
@@ -14,7 +14,6 @@ namespace Composer\Downloader;
use Composer\Config;
use Composer\Package\PackageInterface;
-use Composer\Package\Version\VersionParser;
use Composer\Util\ProcessExecutor;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
@@ -54,7 +53,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
}
- $this->io->writeError(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")");
+ $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
$this->filesystem->emptyDirectory($path);
$urls = $package->getSourceUrls();
@@ -100,8 +99,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
}
$name .= ' '.$initial->getPrettyVersion();
} else {
- $from = VersionParser::formatVersion($initial);
- $to = VersionParser::formatVersion($target);
+ $from = $initial->getFullPrettyVersion();
+ $to = $target->getFullPrettyVersion();
}
$this->io->writeError(" - Updating " . $name . " (" . $from . " => " . $to . ")");
diff --git a/src/Composer/EventDispatcher/Event.php b/src/Composer/EventDispatcher/Event.php
index 38ae4f440..2091f6be0 100644
--- a/src/Composer/EventDispatcher/Event.php
+++ b/src/Composer/EventDispatcher/Event.php
@@ -35,7 +35,7 @@ class Event
protected $flags;
/**
- * @var boolean Whether the event should not be passed to more listeners
+ * @var bool Whether the event should not be passed to more listeners
*/
private $propagationStopped = false;
@@ -86,7 +86,7 @@ class Event
/**
* Checks if stopPropagation has been called
*
- * @return boolean Whether propagation has been stopped
+ * @return bool Whether propagation has been stopped
*/
public function isPropagationStopped()
{
diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php
index 3bb1c8496..721e26a3f 100644
--- a/src/Composer/EventDispatcher/EventDispatcher.php
+++ b/src/Composer/EventDispatcher/EventDispatcher.php
@@ -21,6 +21,7 @@ use Composer\Composer;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Repository\CompositeRepository;
use Composer\Script;
+use Composer\Script\CommandEvent;
use Composer\Script\PackageEvent;
use Composer\Util\ProcessExecutor;
@@ -135,10 +136,10 @@ class EventDispatcher
*
* @param Event $event The event object to pass to the event handlers/listeners.
* @param string $additionalArgs
- * @return int return code of the executed script if any, for php scripts a false return
- * value is changed to 1, anything else to 0
* @throws \RuntimeException
* @throws \Exception
+ * @return int return code of the executed script if any, for php scripts a false return
+ * value is changed to 1, anything else to 0
*/
protected function doDispatch(Event $event)
{
@@ -170,8 +171,14 @@ class EventDispatcher
throw $e;
}
} else {
- $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor','escape'), $event->getArguments()));
- if (0 !== ($exitCode = $this->process->execute($callable . ($args === '' ? '' : ' '.$args)))) {
+ $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor', 'escape'), $event->getArguments()));
+ $exec = $callable . ($args === '' ? '' : ' '.$args);
+ if ($this->io->isVerbose()) {
+ $this->io->writeError(sprintf('> %s: %s', $event->getName(), $exec));
+ } else {
+ $this->io->writeError(sprintf('> %s', $exec));
+ }
+ if (0 !== ($exitCode = $this->process->execute($exec))) {
$this->io->writeError(sprintf('Script %s handling the %s event returned with an error', $callable, $event->getName()));
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
@@ -195,12 +202,18 @@ class EventDispatcher
{
$event = $this->checkListenerExpectedEvent(array($className, $methodName), $event);
+ if ($this->io->isVerbose()) {
+ $this->io->writeError(sprintf('> %s: %s::%s', $event->getName(), $className, $methodName));
+ } else {
+ $this->io->writeError(sprintf('> %s::%s', $className, $methodName));
+ }
+
return $className::$methodName($event);
}
/**
- * @param mixed $target
- * @param Event $event
+ * @param mixed $target
+ * @param Event $event
* @return Event|CommandEvent
*/
protected function checkListenerExpectedEvent($target, Event $event)
@@ -247,7 +260,7 @@ class EventDispatcher
*
* @param string $eventName The event name - typically a constant
* @param Callable $listener A callable expecting an event argument
- * @param integer $priority A higher value represents a higher priority
+ * @param int $priority A higher value represents a higher priority
*/
protected function addListener($eventName, $listener, $priority = 0)
{
@@ -300,8 +313,8 @@ class EventDispatcher
/**
* Checks if an event has listeners registered
*
- * @param Event $event
- * @return boolean
+ * @param Event $event
+ * @return bool
*/
public function hasEventListeners(Event $event)
{
@@ -342,8 +355,8 @@ class EventDispatcher
/**
* Checks if string given references a class path and method
*
- * @param string $callable
- * @return boolean
+ * @param string $callable
+ * @return bool
*/
protected function isPhpScript($callable)
{
diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php
index 19261739f..5f61a243d 100644
--- a/src/Composer/Factory.php
+++ b/src/Composer/Factory.php
@@ -16,6 +16,7 @@ use Composer\Config\JsonConfigSource;
use Composer\Json\JsonFile;
use Composer\IO\IOInterface;
use Composer\Package\Archiver;
+use Composer\Package\Version\VersionGuesser;
use Composer\Repository\RepositoryManager;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Util\ProcessExecutor;
@@ -23,7 +24,7 @@ use Composer\Util\RemoteFilesystem;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Composer\EventDispatcher\EventDispatcher;
use Composer\Autoload\AutoloadGenerator;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
/**
* Creates a configured instance of composer.
@@ -373,7 +374,8 @@ class Factory
// load package
$parser = new VersionParser;
- $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io));
+ $guesser = new VersionGuesser($config, new ProcessExecutor($io), $parser);
+ $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser);
$package = $loader->load($localConfig);
$composer->setPackage($package);
@@ -415,7 +417,7 @@ class Factory
$lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
? substr($composerFile, 0, -4).'lock'
: $composerFile . '.lock';
- $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile));
+ $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, file_get_contents($composerFile));
$composer->setLocker($locker);
}
@@ -440,6 +442,7 @@ class Factory
$rm->setRepositoryClass('perforce', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository');
+ $rm->setRepositoryClass('path', 'Composer\Repository\PathRepository');
return $rm;
}
@@ -512,6 +515,7 @@ class Factory
$dm->setDownloader('gzip', new Downloader\GzipDownloader($io, $config, $eventDispatcher, $cache));
$dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $eventDispatcher, $cache));
$dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $eventDispatcher, $cache));
+ $dm->setDownloader('path', new Downloader\PathDownloader($io, $config, $eventDispatcher, $cache));
return $dm;
}
diff --git a/src/Composer/IO/BufferIO.php b/src/Composer/IO/BufferIO.php
index 581680b7c..db3fb634b 100644
--- a/src/Composer/IO/BufferIO.php
+++ b/src/Composer/IO/BufferIO.php
@@ -23,8 +23,8 @@ use Symfony\Component\Console\Helper\HelperSet;
class BufferIO extends ConsoleIO
{
/**
- * @param string $input
- * @param int $verbosity
+ * @param string $input
+ * @param int $verbosity
* @param OutputFormatterInterface $formatter
*/
public function __construct(
diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php
index 622e73ccf..ae5b952ea 100644
--- a/src/Composer/IO/ConsoleIO.php
+++ b/src/Composer/IO/ConsoleIO.php
@@ -18,7 +18,6 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
-use Symfony\Component\Process\ExecutableFinder;
/**
* The Input/Output helper.
@@ -112,8 +111,8 @@ class ConsoleIO extends BaseIO
/**
* @param array $messages
- * @param boolean $newline
- * @param boolean $stderr
+ * @param bool $newline
+ * @param bool $stderr
*/
private function doWrite($messages, $newline, $stderr)
{
@@ -154,9 +153,9 @@ class ConsoleIO extends BaseIO
/**
* @param array $messages
- * @param boolean $newline
- * @param integer $size
- * @param boolean $stderr
+ * @param bool $newline
+ * @param int $size
+ * @param bool $stderr
*/
private function doOverwrite($messages, $newline, $size, $stderr)
{
diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php
index 7dc9f5a09..b26700a8c 100644
--- a/src/Composer/IO/IOInterface.php
+++ b/src/Composer/IO/IOInterface.php
@@ -77,7 +77,7 @@ interface IOInterface
*
* @param string|array $messages The message as an array of lines or a single string
* @param bool $newline Whether to add a newline or not
- * @param integer $size The size of line
+ * @param int $size The size of line
*/
public function overwrite($messages, $newline = true, $size = null);
@@ -86,7 +86,7 @@ interface IOInterface
*
* @param string|array $messages The message as an array of lines or a single string
* @param bool $newline Whether to add a newline or not
- * @param integer $size The size of line
+ * @param int $size The size of line
*/
public function overwriteError($messages, $newline = true, $size = null);
@@ -96,9 +96,8 @@ interface IOInterface
* @param string|array $question The question to ask
* @param string $default The default answer if none is given by the user
*
- * @return string The user answer
- *
* @throws \RuntimeException If there is no data to read in the input stream
+ * @return string The user answer
*/
public function ask($question, $default = null);
@@ -123,12 +122,11 @@ interface IOInterface
*
* @param string|array $question The question to ask
* @param callback $validator A PHP callback
- * @param null|integer $attempts Max number of times to ask before giving up (default of null means infinite)
+ * @param null|int $attempts Max number of times to ask before giving up (default of null means infinite)
* @param string $default The default answer if none is given by the user
*
- * @return mixed
- *
* @throws \Exception When any of the validators return an error
+ * @return mixed
*/
public function askAndValidate($question, $validator, $attempts = null, $default = null);
@@ -153,7 +151,7 @@ interface IOInterface
*
* @param string $repositoryName The unique name of repository
*
- * @return boolean
+ * @return bool
*/
public function hasAuthentication($repositoryName);
diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php
index e58381856..5f1299a97 100644
--- a/src/Composer/Installer.php
+++ b/src/Composer/Installer.php
@@ -18,6 +18,7 @@ use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\OperationInterface;
+use Composer\DependencyResolver\PolicyInterface;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
use Composer\DependencyResolver\Rule;
@@ -33,7 +34,7 @@ use Composer\Json\JsonFile;
use Composer\Package\AliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\Link;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
use Composer\Package\Locker;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
@@ -43,6 +44,7 @@ use Composer\Repository\InstalledFilesystemRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\RepositoryManager;
+use Composer\Repository\WritableRepositoryInterface;
use Composer\Script\ScriptEvents;
/**
@@ -101,6 +103,7 @@ class Installer
protected $preferSource = false;
protected $preferDist = false;
protected $optimizeAutoloader = false;
+ protected $classMapAuthoritative = false;
protected $devMode = false;
protected $dryRun = false;
protected $verbose = false;
@@ -157,9 +160,8 @@ class Installer
/**
* Run installation (or update)
*
- * @return int 0 on success or a positive error code on failure
- *
* @throws \Exception
+ * @return int 0 on success or a positive error code on failure
*/
public function run()
{
@@ -333,6 +335,7 @@ class Installer
}
$this->autoloadGenerator->setDevMode($this->devMode);
+ $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative);
$this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader);
}
@@ -344,13 +347,23 @@ class Installer
$vendorDir = $this->config->get('vendor-dir');
if (is_dir($vendorDir)) {
- touch($vendorDir);
+ // suppress errors as this fails sometimes on OSX for no apparent reason
+ // see https://github.com/composer/composer/issues/4070#issuecomment-129792748
+ @touch($vendorDir);
}
}
return 0;
}
+ /**
+ * @param RepositoryInterface $localRepo
+ * @param RepositoryInterface $installedRepo
+ * @param PlatformRepository $platformRepo
+ * @param array $aliases
+ * @param bool $withDevReqs
+ * @return int
+ */
protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases, $withDevReqs)
{
// init vars
@@ -414,7 +427,7 @@ class Installer
&& $this->installationManager->isPackageInstalled($localRepo, $package)
) {
$removedUnstablePackages[$package->getName()] = true;
- $request->remove($package->getName(), new VersionConstraint('=', $package->getVersion()));
+ $request->remove($package->getName(), new Constraint('=', $package->getVersion()));
}
}
}
@@ -453,7 +466,7 @@ class Installer
foreach ($currentPackages as $curPackage) {
if ($curPackage->getName() === $candidate) {
if (!$this->isUpdateable($curPackage) && !isset($removedUnstablePackages[$curPackage->getName()])) {
- $constraint = new VersionConstraint('=', $curPackage->getVersion());
+ $constraint = new Constraint('=', $curPackage->getVersion());
$request->install($curPackage->getName(), $constraint);
}
break;
@@ -473,7 +486,7 @@ class Installer
if (isset($aliases[$package->getName()][$version])) {
$version = $aliases[$package->getName()][$version]['alias_normalized'];
}
- $constraint = new VersionConstraint('=', $version);
+ $constraint = new Constraint('=', $version);
$constraint->setPrettyString($package->getPrettyVersion());
$request->install($package->getName(), $constraint);
}
@@ -511,6 +524,11 @@ class Installer
return max(1, $e->getCode());
}
+ if ($this->io->isVerbose()) {
+ $this->io->writeError("Analyzed ".count($pool)." packages to resolve dependencies");
+ $this->io->writeError("Analyzed ".$solver->getRuleSetSize()." rules to resolve dependencies");
+ }
+
// force dev packages to be updated if we update or install from a (potentially new) lock
$operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $installFromLock, $withDevReqs, 'force-updates', $operations);
@@ -552,7 +570,8 @@ class Installer
if ('update' === $operation->getJobType()
&& $operation->getTargetPackage()->isDev()
&& $operation->getTargetPackage()->getVersion() === $operation->getInitialPackage()->getVersion()
- && $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference()
+ && (!$operation->getTargetPackage()->getSourceReference() || $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference())
+ && (!$operation->getTargetPackage()->getDistReference() || $operation->getTargetPackage()->getDistReference() === $operation->getInitialPackage()->getDistReference())
) {
if ($this->io->isDebug()) {
$this->io->writeError(' - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version');
@@ -608,7 +627,7 @@ class Installer
if (!$this->dryRun) {
// force source/dist urls to be updated for all packages
- $operations = $this->processPackageUrls($pool, $policy, $localRepo, $repositories);
+ $this->processPackageUrls($pool, $policy, $localRepo, $repositories);
$localRepo->write();
}
@@ -679,6 +698,11 @@ class Installer
return array_merge($uninstOps, $operations);
}
+ /**
+ * @param bool $withDevReqs
+ * @param RepositoryInterface|null $lockedRepository
+ * @return Pool
+ */
private function createPool($withDevReqs, RepositoryInterface $lockedRepository = null)
{
if (!$this->update && $this->locker->isLocked()) { // install from lock
@@ -687,7 +711,7 @@ class Installer
$requires = array();
foreach ($lockedRepository->getPackages() as $package) {
- $constraint = new VersionConstraint('=', $package->getVersion());
+ $constraint = new Constraint('=', $package->getVersion());
$constraint->setPrettyString($package->getPrettyVersion());
$requires[$package->getName()] = $constraint;
}
@@ -717,6 +741,9 @@ class Installer
return new Pool($minimumStability, $stabilityFlags, $rootConstraints);
}
+ /**
+ * @return DefaultPolicy
+ */
private function createPolicy()
{
$preferStable = null;
@@ -737,11 +764,16 @@ class Installer
return new DefaultPolicy($preferStable, $preferLowest);
}
+ /**
+ * @param RootPackageInterface $rootPackage
+ * @param PlatformRepository $platformRepo
+ * @return Request
+ */
private function createRequest(RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
{
$request = new Request();
- $constraint = new VersionConstraint('=', $rootPackage->getVersion());
+ $constraint = new Constraint('=', $rootPackage->getVersion());
$constraint->setPrettyString($rootPackage->getPrettyVersion());
$request->install($rootPackage->getName(), $constraint);
@@ -755,7 +787,7 @@ class Installer
// to prevent the solver trying to remove or update those
$provided = $rootPackage->getProvides();
foreach ($fixedPackages as $package) {
- $constraint = new VersionConstraint('=', $package->getVersion());
+ $constraint = new Constraint('=', $package->getVersion());
$constraint->setPrettyString($package->getPrettyVersion());
// skip platform packages that are provided by the root package
@@ -770,6 +802,19 @@ class Installer
return $request;
}
+ /**
+ * @param WritableRepositoryInterface $localRepo
+ * @param Pool $pool
+ * @param PolicyInterface $policy
+ * @param array $repositories
+ * @param RepositoryInterface $installedRepo
+ * @param RepositoryInterface $lockedRepository
+ * @param bool $installFromLock
+ * @param bool $withDevReqs
+ * @param string $task
+ * @param array|null $operations
+ * @return array
+ */
private function processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $installFromLock, $withDevReqs, $task, array $operations = null)
{
if ($task === 'force-updates' && null === $operations) {
@@ -847,7 +892,7 @@ class Installer
}
// find similar packages (name/version) in all repositories
- $matches = $pool->whatProvides($package->getName(), new VersionConstraint('=', $package->getVersion()));
+ $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
foreach ($matches as $index => $match) {
// skip local packages
if (!in_array($match->getRepository(), $repositories, true)) {
@@ -902,6 +947,9 @@ class Installer
/**
* Loads the most "current" list of packages that are installed meaning from lock ideally or from installed repo as fallback
+ * @param bool $withDevReqs
+ * @param RepositoryInterface $installedRepo
+ * @return array
*/
private function getCurrentPackages($withDevReqs, $installedRepo)
{
@@ -917,6 +965,9 @@ class Installer
return $installedRepo->getPackages();
}
+ /**
+ * @return array
+ */
private function getRootAliases()
{
if (!$this->update && $this->locker->isLocked()) {
@@ -930,13 +981,19 @@ class Installer
foreach ($aliases as $alias) {
$normalizedAliases[$alias['package']][$alias['version']] = array(
'alias' => $alias['alias'],
- 'alias_normalized' => $alias['alias_normalized']
+ 'alias_normalized' => $alias['alias_normalized'],
);
}
return $normalizedAliases;
}
+ /**
+ * @param Pool $pool
+ * @param PolicyInterface $policy
+ * @param WritableRepositoryInterface $localRepo
+ * @param array $repositories
+ */
private function processPackageUrls($pool, $policy, $localRepo, $repositories)
{
if (!$this->update) {
@@ -945,7 +1002,7 @@ class Installer
foreach ($localRepo->getCanonicalPackages() as $package) {
// find similar packages (name/version) in all repositories
- $matches = $pool->whatProvides($package->getName(), new VersionConstraint('=', $package->getVersion()));
+ $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
foreach ($matches as $index => $match) {
// skip local packages
if (!in_array($match->getRepository(), $repositories, true)) {
@@ -967,7 +1024,15 @@ class Installer
$newPackage = $pool->literalToPackage($matches[0]);
// update the dist and source URLs
- $package->setSourceUrl($newPackage->getSourceUrl());
+ $sourceUrl = $package->getSourceUrl();
+ $newSourceUrl = $newPackage->getSourceUrl();
+
+ if ($sourceUrl !== $newSourceUrl) {
+ $package->setSourceType($newPackage->getSourceType());
+ $package->setSourceUrl($newSourceUrl);
+ $package->setSourceReference($newPackage->getSourceReference());
+ }
+
// only update dist url for github/bitbucket dists as they use a combination of dist url + dist reference to install
// but for other urls this is ambiguous and could result in bad outcomes
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com)/}', $newPackage->getDistUrl())) {
@@ -977,6 +1042,10 @@ class Installer
}
}
+ /**
+ * @param PlatformRepository $platformRepo
+ * @param array $aliases
+ */
private function aliasPlatformPackages(PlatformRepository $platformRepo, $aliases)
{
foreach ($aliases as $package => $versions) {
@@ -991,6 +1060,10 @@ class Installer
}
}
+ /**
+ * @param PackageInterface $package
+ * @return bool
+ */
private function isUpdateable(PackageInterface $package)
{
if (!$this->updateWhitelist) {
@@ -1020,6 +1093,10 @@ class Installer
return "{^" . $cleanedWhiteListedPattern . "$}i";
}
+ /**
+ * @param array $links
+ * @return array
+ */
private function extractPlatformRequirements($links)
{
$platformReqs = array();
@@ -1040,7 +1117,7 @@ class Installer
* update whitelist themselves.
*
* @param RepositoryInterface $localRepo
- * @param boolean $devMode
+ * @param bool $devMode
* @param array $rootRequires An array of links to packages in require of the root package
* @param array $rootDevRequires An array of links to packages in require-dev of the root package
*/
@@ -1172,6 +1249,10 @@ class Installer
);
}
+ /**
+ * @param RepositoryInterface $additionalInstalledRepository
+ * @return $this
+ */
public function setAdditionalInstalledRepository(RepositoryInterface $additionalInstalledRepository)
{
$this->additionalInstalledRepository = $additionalInstalledRepository;
@@ -1182,7 +1263,7 @@ class Installer
/**
* Whether to run in drymode or not
*
- * @param boolean $dryRun
+ * @param bool $dryRun
* @return Installer
*/
public function setDryRun($dryRun = true)
@@ -1205,7 +1286,7 @@ class Installer
/**
* prefer source installation
*
- * @param boolean $preferSource
+ * @param bool $preferSource
* @return Installer
*/
public function setPreferSource($preferSource = true)
@@ -1218,7 +1299,7 @@ class Installer
/**
* prefer dist installation
*
- * @param boolean $preferDist
+ * @param bool $preferDist
* @return Installer
*/
public function setPreferDist($preferDist = true)
@@ -1237,6 +1318,29 @@ class Installer
public function setOptimizeAutoloader($optimizeAutoloader = false)
{
$this->optimizeAutoloader = (boolean) $optimizeAutoloader;
+ if (!$this->optimizeAutoloader) {
+ // Force classMapAuthoritative off when not optimizing the
+ // autoloader
+ $this->setClassMapAuthoritative(false);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Whether or not generated autoloader considers the class map
+ * authoritative.
+ *
+ * @param bool $classMapAuthoritative
+ * @return Installer
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative = false)
+ {
+ $this->classMapAuthoritative = (boolean) $classMapAuthoritative;
+ if ($this->classMapAuthoritative) {
+ // Force optimizeAutoloader when classmap is authoritative
+ $this->setOptimizeAutoloader(true);
+ }
return $this;
}
@@ -1244,7 +1348,7 @@ class Installer
/**
* update packages
*
- * @param boolean $update
+ * @param bool $update
* @return Installer
*/
public function setUpdate($update = true)
@@ -1257,7 +1361,7 @@ class Installer
/**
* enables dev packages
*
- * @param boolean $devMode
+ * @param bool $devMode
* @return Installer
*/
public function setDevMode($devMode = true)
@@ -1270,7 +1374,7 @@ class Installer
/**
* set whether to run autoloader or not
*
- * @param boolean $dumpAutoloader
+ * @param bool $dumpAutoloader
* @return Installer
*/
public function setDumpAutoloader($dumpAutoloader = true)
@@ -1283,7 +1387,7 @@ class Installer
/**
* set whether to run scripts or not
*
- * @param boolean $runScripts
+ * @param bool $runScripts
* @return Installer
*/
public function setRunScripts($runScripts = true)
@@ -1309,7 +1413,7 @@ class Installer
/**
* run in verbose mode
*
- * @param boolean $verbose
+ * @param bool $verbose
* @return Installer
*/
public function setVerbose($verbose = true)
@@ -1332,7 +1436,7 @@ class Installer
/**
* set ignore Platform Package requirements
*
- * @param boolean $ignorePlatformReqs
+ * @param bool $ignorePlatformReqs
* @return Installer
*/
public function setIgnorePlatformRequirements($ignorePlatformReqs = false)
@@ -1359,7 +1463,7 @@ class Installer
/**
* Should dependencies of whitelisted packages be updated recursively?
*
- * @param boolean $updateDependencies
+ * @param bool $updateDependencies
* @return Installer
*/
public function setWhitelistDependencies($updateDependencies = true)
@@ -1372,7 +1476,7 @@ class Installer
/**
* Should packages be preferred in a stable version when updating?
*
- * @param boolean $preferStable
+ * @param bool $preferStable
* @return Installer
*/
public function setPreferStable($preferStable = true)
@@ -1385,7 +1489,7 @@ class Installer
/**
* Should packages be preferred in a lowest version when updating?
*
- * @param boolean $preferLowest
+ * @param bool $preferLowest
* @return Installer
*/
public function setPreferLowest($preferLowest = true)
diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php
index a43acbbda..b774f83c9 100644
--- a/src/Composer/Installer/InstallationManager.php
+++ b/src/Composer/Installer/InstallationManager.php
@@ -89,9 +89,8 @@ class InstallationManager
*
* @param string $type package type
*
- * @return InstallerInterface
- *
* @throws \InvalidArgumentException if installer for provided type is not registered
+ * @return InstallerInterface
*/
public function getInstaller($type)
{
@@ -249,7 +248,7 @@ class InstallationManager
'header' => array('Content-type: application/x-www-form-urlencoded'),
'content' => http_build_query($params, '', '&'),
'timeout' => 3,
- )
+ ),
);
$context = StreamContextFactory::getContext($url, $opts);
@@ -273,7 +272,7 @@ class InstallationManager
'header' => array('Content-Type: application/json'),
'content' => json_encode($postData),
'timeout' => 6,
- )
+ ),
);
$context = StreamContextFactory::getContext($repoUrl, $opts);
diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php
index 469b91ed4..e64dfadd2 100644
--- a/src/Composer/Installer/InstallerInterface.php
+++ b/src/Composer/Installer/InstallerInterface.php
@@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
+use InvalidArgumentException;
/**
* Interface for the package installation manager.
diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php
index aa2d46062..75b3a0c6e 100644
--- a/src/Composer/Installer/LibraryInstaller.php
+++ b/src/Composer/Installer/LibraryInstaller.php
@@ -266,6 +266,11 @@ class LibraryInstaller implements InstallerInterface
$this->filesystem->unlink($link.'.bat');
}
}
+
+ // attempt removing the bin dir in case it is left empty
+ if ((is_dir($this->binDir)) && ($this->filesystem->isDirEmpty($this->binDir))) {
+ @rmdir($this->binDir);
+ }
}
protected function initializeVendorDir()
diff --git a/src/Composer/Installer/PackageEvent.php b/src/Composer/Installer/PackageEvent.php
index e1c5e6080..f5cf0ed6e 100644
--- a/src/Composer/Installer/PackageEvent.php
+++ b/src/Composer/Installer/PackageEvent.php
@@ -18,7 +18,6 @@ use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\PolicyInterface;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
-use Composer\EventDispatcher\Event;
use Composer\Repository\CompositeRepository;
/**
diff --git a/src/Composer/Installer/PluginInstaller.php b/src/Composer/Installer/PluginInstaller.php
index ddb8e5bdd..14aec4462 100644
--- a/src/Composer/Installer/PluginInstaller.php
+++ b/src/Composer/Installer/PluginInstaller.php
@@ -13,7 +13,6 @@
namespace Composer\Installer;
use Composer\Composer;
-use Composer\Package\Package;
use Composer\IO\IOInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
@@ -27,7 +26,6 @@ use Composer\Package\PackageInterface;
class PluginInstaller extends LibraryInstaller
{
private $installationManager;
- private static $classCounter = 0;
/**
* Initializes Plugin installer.
diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php
index 1c51a4251..ee4f04e84 100644
--- a/src/Composer/Json/JsonFile.php
+++ b/src/Composer/Json/JsonFile.php
@@ -137,8 +137,8 @@ class JsonFile
* Validates the schema of the current json file according to composer-schema.json rules
*
* @param int $schema a JsonFile::*_SCHEMA constant
- * @return bool true on success
* @throws JsonValidationException
+ * @return bool true on success
*/
public function validateSchema($schema = self::STRICT_SCHEMA)
{
@@ -218,7 +218,7 @@ class JsonFile
/**
* Throws an exception according to a given code with a customized message
*
- * @param int $code return code of json_last_error function
+ * @param int $code return code of json_last_error function
* @throws \RuntimeException
*/
private static function throwEncodeError($code)
@@ -269,10 +269,10 @@ class JsonFile
*
* @param string $json
* @param string $file
- * @return bool true on success
* @throws \UnexpectedValueException
* @throws JsonValidationException
* @throws ParsingException
+ * @return bool true on success
*/
protected static function validateSyntax($json, $file = null)
{
diff --git a/src/Composer/Json/JsonFormatter.php b/src/Composer/Json/JsonFormatter.php
index d109acae8..8e2005715 100644
--- a/src/Composer/Json/JsonFormatter.php
+++ b/src/Composer/Json/JsonFormatter.php
@@ -23,7 +23,6 @@ namespace Composer\Json;
class JsonFormatter
{
/**
- *
* This code is based on the function found at:
* http://recursive-design.com/blog/2008/03/11/format-json-with-php/
*
diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php
index f6aa98a4c..8e1bb88fe 100644
--- a/src/Composer/Package/AliasPackage.php
+++ b/src/Composer/Package/AliasPackage.php
@@ -12,8 +12,8 @@
namespace Composer\Package;
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+use Composer\Semver\VersionParser;
/**
* @author Jordi Boggiano
@@ -162,7 +162,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
}
/**
- * @param array $links
+ * @param array $links
* @param string $linkType
* @internal param string $prettyVersion
* @return array
@@ -174,14 +174,14 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
foreach ($links as $link) {
// link is self.version, but must be replacing also the replaced version
if ('self.version' === $link->getPrettyConstraint()) {
- $newLinks[] = new Link($link->getSource(), $link->getTarget(), new VersionConstraint('=', $this->version), $linkType, $this->prettyVersion);
+ $newLinks[] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
}
}
$links = array_merge($links, $newLinks);
} else {
foreach ($links as $index => $link) {
if ('self.version' === $link->getPrettyConstraint()) {
- $links[$index] = new Link($link->getSource(), $link->getTarget(), new VersionConstraint('=', $this->version), $linkType, $this->prettyVersion);
+ $links[$index] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
}
}
}
diff --git a/src/Composer/Package/Archiver/ArchivableFilesFinder.php b/src/Composer/Package/Archiver/ArchivableFilesFinder.php
index 44c682616..1e94f1e15 100644
--- a/src/Composer/Package/Archiver/ArchivableFilesFinder.php
+++ b/src/Composer/Package/Archiver/ArchivableFilesFinder.php
@@ -13,8 +13,7 @@
namespace Composer\Package\Archiver;
use Composer\Util\Filesystem;
-
-use Symfony\Component\Finder;
+use Symfony\Component\Finder\Finder;
/**
* A Symfony Finder wrapper which locates files that should go into archives
@@ -27,7 +26,7 @@ use Symfony\Component\Finder;
class ArchivableFilesFinder extends \FilterIterator
{
/**
- * @var Symfony\Component\Finder\Finder
+ * @var Finder
*/
protected $finder;
@@ -49,7 +48,7 @@ class ArchivableFilesFinder extends \FilterIterator
new ComposerExcludeFilter($sources, $excludes),
);
- $this->finder = new Finder\Finder();
+ $this->finder = new Finder();
$filter = function (\SplFileInfo $file) use ($sources, $filters, $fs) {
if ($file->isLink() && strpos($file->getLinkTarget(), $sources) !== 0) {
diff --git a/src/Composer/Package/Archiver/ArchiverInterface.php b/src/Composer/Package/Archiver/ArchiverInterface.php
index 72a06c1c9..a625f5c07 100644
--- a/src/Composer/Package/Archiver/ArchiverInterface.php
+++ b/src/Composer/Package/Archiver/ArchiverInterface.php
@@ -37,7 +37,7 @@ interface ArchiverInterface
* @param string $format The archive format
* @param string $sourceType The source type (git, svn, hg, etc.)
*
- * @return boolean true if the format is supported by the archiver
+ * @return bool true if the format is supported by the archiver
*/
public function supports($format, $sourceType);
}
diff --git a/src/Composer/Package/Archiver/BaseExcludeFilter.php b/src/Composer/Package/Archiver/BaseExcludeFilter.php
index d724f31e4..c94c52a6b 100644
--- a/src/Composer/Package/Archiver/BaseExcludeFilter.php
+++ b/src/Composer/Package/Archiver/BaseExcludeFilter.php
@@ -123,7 +123,7 @@ abstract class BaseExcludeFilter
protected function generatePattern($rule)
{
$negate = false;
- $pattern = '#';
+ $pattern = '{';
if (strlen($rule) && $rule[0] === '!') {
$negate = true;
@@ -143,6 +143,6 @@ abstract class BaseExcludeFilter
// remove delimiters as well as caret (^) and dollar sign ($) from the regex
$pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)';
- return array($pattern . '#', $negate, false);
+ return array($pattern . '}', $negate, false);
}
}
diff --git a/src/Composer/Package/Archiver/HgExcludeFilter.php b/src/Composer/Package/Archiver/HgExcludeFilter.php
index fa2327c5f..b9c81cdc1 100644
--- a/src/Composer/Package/Archiver/HgExcludeFilter.php
+++ b/src/Composer/Package/Archiver/HgExcludeFilter.php
@@ -26,7 +26,7 @@ class HgExcludeFilter extends BaseExcludeFilter
/**
* Either HG_IGNORE_REGEX or HG_IGNORE_GLOB
- * @var integer
+ * @var int
*/
protected $patternMode;
diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php
index 965e5ddc8..0369a36dd 100644
--- a/src/Composer/Package/BasePackage.php
+++ b/src/Composer/Package/BasePackage.php
@@ -161,7 +161,7 @@ abstract class BasePackage implements PackageInterface
/**
* checks if this package is a platform package
*
- * @return boolean
+ * @return bool
*/
public function isPlatform()
{
@@ -206,6 +206,23 @@ abstract class BasePackage implements PackageInterface
return $this->getPrettyName().' '.$this->getPrettyVersion();
}
+ /**
+ * {@inheritDoc}
+ */
+ public function getFullPrettyVersion($truncate = true)
+ {
+ if (!$this->isDev() || !in_array($this->getSourceType(), array('hg', 'git'))) {
+ return $this->getPrettyVersion();
+ }
+
+ // if source reference is a sha1 hash -- truncate
+ if ($truncate && strlen($this->getSourceReference()) === 40) {
+ return $this->getPrettyVersion() . ' ' . substr($this->getSourceReference(), 0, 7);
+ }
+
+ return $this->getPrettyVersion() . ' ' . $this->getSourceReference();
+ }
+
public function __clone()
{
$this->repository = null;
diff --git a/src/Composer/Package/CompletePackage.php b/src/Composer/Package/CompletePackage.php
index 0de1609d0..0a926a4ce 100644
--- a/src/Composer/Package/CompletePackage.php
+++ b/src/Composer/Package/CompletePackage.php
@@ -172,7 +172,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
- * @return boolean
+ * @return bool
*/
public function isAbandoned()
{
@@ -180,7 +180,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
- * @param boolean|string $abandoned
+ * @param bool|string $abandoned
*/
public function setAbandoned($abandoned)
{
diff --git a/src/Composer/Package/CompletePackageInterface.php b/src/Composer/Package/CompletePackageInterface.php
index 8263a6535..4036b3cec 100644
--- a/src/Composer/Package/CompletePackageInterface.php
+++ b/src/Composer/Package/CompletePackageInterface.php
@@ -82,7 +82,7 @@ interface CompletePackageInterface extends PackageInterface
/**
* Returns if the package is abandoned or not
*
- * @return boolean
+ * @return bool
*/
public function isAbandoned();
diff --git a/src/Composer/Package/Link.php b/src/Composer/Package/Link.php
index e09f163eb..e695822fd 100644
--- a/src/Composer/Package/Link.php
+++ b/src/Composer/Package/Link.php
@@ -12,7 +12,7 @@
namespace Composer\Package;
-use Composer\Package\LinkConstraint\LinkConstraintInterface;
+use Composer\Semver\Constraint\ConstraintInterface;
/**
* Represents a link between two packages, represented by their names
@@ -32,7 +32,7 @@ class Link
protected $target;
/**
- * @var LinkConstraintInterface|null
+ * @var ConstraintInterface|null
*/
protected $constraint;
@@ -49,13 +49,13 @@ class Link
/**
* Creates a new package link.
*
- * @param string $source
- * @param string $target
- * @param LinkConstraintInterface|null $constraint Constraint applying to the target of this link
- * @param string $description Used to create a descriptive string representation
- * @param string|null $prettyConstraint
+ * @param string $source
+ * @param string $target
+ * @param ConstraintInterface|null $constraint Constraint applying to the target of this link
+ * @param string $description Used to create a descriptive string representation
+ * @param string|null $prettyConstraint
*/
- public function __construct($source, $target, LinkConstraintInterface $constraint = null, $description = 'relates to', $prettyConstraint = null)
+ public function __construct($source, $target, ConstraintInterface $constraint = null, $description = 'relates to', $prettyConstraint = null)
{
$this->source = strtolower($source);
$this->target = strtolower($target);
@@ -81,7 +81,7 @@ class Link
}
/**
- * @return LinkConstraintInterface|null
+ * @return ConstraintInterface|null
*/
public function getConstraint()
{
@@ -110,7 +110,7 @@ class Link
}
/**
- * @param PackageInterface $sourcePackage
+ * @param PackageInterface $sourcePackage
* @return string
*/
public function getPrettyString(PackageInterface $sourcePackage)
diff --git a/src/Composer/Package/LinkConstraint/EmptyConstraint.php b/src/Composer/Package/LinkConstraint/EmptyConstraint.php
index ca1c75ff5..09eb15ada 100644
--- a/src/Composer/Package/LinkConstraint/EmptyConstraint.php
+++ b/src/Composer/Package/LinkConstraint/EmptyConstraint.php
@@ -12,36 +12,13 @@
namespace Composer\Package\LinkConstraint;
+use Composer\Semver\Constraint\EmptyConstraint as SemverEmptyConstraint;
+
+@trigger_error('The ' . __NAMESPACE__ . '\EmptyConstraint class is deprecated, use Composer\Semver\Constraint\EmptyConstraint instead.', E_USER_DEPRECATED);
+
/**
- * Defines an absence of constraints
- *
- * @author Jordi Boggiano
+ * @deprecated use Composer\Semver\Constraint\EmptyConstraint instead
*/
-class EmptyConstraint implements LinkConstraintInterface
+class EmptyConstraint extends SemverEmptyConstraint implements LinkConstraintInterface
{
- protected $prettyString;
-
- public function matches(LinkConstraintInterface $provider)
- {
- return true;
- }
-
- public function setPrettyString($prettyString)
- {
- $this->prettyString = $prettyString;
- }
-
- public function getPrettyString()
- {
- if ($this->prettyString) {
- return $this->prettyString;
- }
-
- return $this->__toString();
- }
-
- public function __toString()
- {
- return '[]';
- }
}
diff --git a/src/Composer/Package/LinkConstraint/LinkConstraintInterface.php b/src/Composer/Package/LinkConstraint/LinkConstraintInterface.php
index 199c9fc42..bac98c6f9 100644
--- a/src/Composer/Package/LinkConstraint/LinkConstraintInterface.php
+++ b/src/Composer/Package/LinkConstraint/LinkConstraintInterface.php
@@ -12,15 +12,13 @@
namespace Composer\Package\LinkConstraint;
+use Composer\Semver\Constraint\ConstraintInterface;
+
+@trigger_error('The ' . __NAMESPACE__ . '\LinkConstraintInterface interface is deprecated, use Composer\Semver\Constraint\ConstraintInterface instead.', E_USER_DEPRECATED);
+
/**
- * Defines a constraint on a link between two packages.
- *
- * @author Nils Adermann
+ * @deprecated use Composer\Semver\Constraint\ConstraintInterface instead
*/
-interface LinkConstraintInterface
+interface LinkConstraintInterface extends ConstraintInterface
{
- public function matches(LinkConstraintInterface $provider);
- public function setPrettyString($prettyString);
- public function getPrettyString();
- public function __toString();
}
diff --git a/src/Composer/Package/LinkConstraint/MultiConstraint.php b/src/Composer/Package/LinkConstraint/MultiConstraint.php
index 3871aeb2f..6e091a430 100644
--- a/src/Composer/Package/LinkConstraint/MultiConstraint.php
+++ b/src/Composer/Package/LinkConstraint/MultiConstraint.php
@@ -12,72 +12,13 @@
namespace Composer\Package\LinkConstraint;
+use Composer\Semver\Constraint\MultiConstraint as SemverMultiConstraint;
+
+@trigger_error('The ' . __NAMESPACE__ . '\MultiConstraint class is deprecated, use Composer\Semver\Constraint\MultiConstraint instead.', E_USER_DEPRECATED);
+
/**
- * Defines a conjunctive or disjunctive set of constraints on the target of a package link
- *
- * @author Nils Adermann
- * @author Jordi Boggiano
+ * @deprecated use Composer\Semver\Constraint\MultiConstraint instead
*/
-class MultiConstraint implements LinkConstraintInterface
+class MultiConstraint extends SemverMultiConstraint implements LinkConstraintInterface
{
- protected $constraints;
- protected $prettyString;
- protected $conjunctive;
-
- /**
- * Sets operator and version to compare a package with
- *
- * @param array $constraints A set of constraints
- * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
- */
- public function __construct(array $constraints, $conjunctive = true)
- {
- $this->constraints = $constraints;
- $this->conjunctive = $conjunctive;
- }
-
- public function matches(LinkConstraintInterface $provider)
- {
- if (false === $this->conjunctive) {
- foreach ($this->constraints as $constraint) {
- if ($constraint->matches($provider)) {
- return true;
- }
- }
-
- return false;
- }
-
- foreach ($this->constraints as $constraint) {
- if (!$constraint->matches($provider)) {
- return false;
- }
- }
-
- return true;
- }
-
- public function setPrettyString($prettyString)
- {
- $this->prettyString = $prettyString;
- }
-
- public function getPrettyString()
- {
- if ($this->prettyString) {
- return $this->prettyString;
- }
-
- return $this->__toString();
- }
-
- public function __toString()
- {
- $constraints = array();
- foreach ($this->constraints as $constraint) {
- $constraints[] = $constraint->__toString();
- }
-
- return '['.implode($this->conjunctive ? ' ' : ' || ', $constraints).']';
- }
}
diff --git a/src/Composer/Package/LinkConstraint/SpecificConstraint.php b/src/Composer/Package/LinkConstraint/SpecificConstraint.php
index e0904dbbf..880873887 100644
--- a/src/Composer/Package/LinkConstraint/SpecificConstraint.php
+++ b/src/Composer/Package/LinkConstraint/SpecificConstraint.php
@@ -12,42 +12,13 @@
namespace Composer\Package\LinkConstraint;
+use Composer\Semver\Constraint\AbstractConstraint;
+
+@trigger_error('The ' . __NAMESPACE__ . '\SpecificConstraint abstract class is deprecated, use Composer\Semver\Constraint\AbstractConstraint instead.', E_USER_DEPRECATED);
+
/**
- * Provides a common basis for specific package link constraints
- *
- * @author Nils Adermann
+ * @deprecated use Composer\Semver\Constraint\AbstractConstraint instead
*/
-abstract class SpecificConstraint implements LinkConstraintInterface
+abstract class SpecificConstraint extends AbstractConstraint implements LinkConstraintInterface
{
- protected $prettyString;
-
- public function matches(LinkConstraintInterface $provider)
- {
- if ($provider instanceof MultiConstraint) {
- // turn matching around to find a match
- return $provider->matches($this);
- } elseif ($provider instanceof $this) {
- return $this->matchSpecific($provider);
- }
-
- return true;
- }
-
- public function setPrettyString($prettyString)
- {
- $this->prettyString = $prettyString;
- }
-
- public function getPrettyString()
- {
- if ($this->prettyString) {
- return $this->prettyString;
- }
-
- return $this->__toString();
- }
-
- // implementations must implement a method of this format:
- // not declared abstract here because type hinting violates parameter coherence (TODO right word?)
- // public function matchSpecific( $provider);
}
diff --git a/src/Composer/Package/LinkConstraint/VersionConstraint.php b/src/Composer/Package/LinkConstraint/VersionConstraint.php
index cd2336227..580016795 100644
--- a/src/Composer/Package/LinkConstraint/VersionConstraint.php
+++ b/src/Composer/Package/LinkConstraint/VersionConstraint.php
@@ -12,113 +12,13 @@
namespace Composer\Package\LinkConstraint;
+use Composer\Semver\Constraint\Constraint;
+
+@trigger_error('The ' . __NAMESPACE__ . '\VersionConstraint class is deprecated, use Composer\Semver\Constraint\Constraint instead.', E_USER_DEPRECATED);
+
/**
- * Constrains a package link based on package version
- *
- * Version numbers must be compatible with version_compare
- *
- * @author Nils Adermann
+ * @deprecated use Composer\Semver\Constraint\Constraint instead
*/
-class VersionConstraint extends SpecificConstraint
+class VersionConstraint extends Constraint implements LinkConstraintInterface
{
- private $operator;
- private $version;
-
- /**
- * Sets operator and version to compare a package with
- *
- * @param string $operator A comparison operator
- * @param string $version A version to compare to
- */
- public function __construct($operator, $version)
- {
- if ('=' === $operator) {
- $operator = '==';
- }
-
- if ('<>' === $operator) {
- $operator = '!=';
- }
-
- $this->operator = $operator;
- $this->version = $version;
- }
-
- public function versionCompare($a, $b, $operator, $compareBranches = false)
- {
- $aIsBranch = 'dev-' === substr($a, 0, 4);
- $bIsBranch = 'dev-' === substr($b, 0, 4);
- if ($aIsBranch && $bIsBranch) {
- return $operator == '==' && $a === $b;
- }
-
- // when branches are not comparable, we make sure dev branches never match anything
- if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
- return false;
- }
-
- return version_compare($a, $b, $operator);
- }
-
- /**
- * @param VersionConstraint $provider
- * @param bool $compareBranches
- * @return bool
- */
- public function matchSpecific(VersionConstraint $provider, $compareBranches = false)
- {
- static $cache = array();
- if (isset($cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches])) {
- return $cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches];
- }
-
- return $cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches] =
- $this->doMatchSpecific($provider, $compareBranches);
- }
-
- /**
- * @param VersionConstraint $provider
- * @param bool $compareBranches
- * @return bool
- */
- private function doMatchSpecific(VersionConstraint $provider, $compareBranches = false)
- {
- $noEqualOp = str_replace('=', '', $this->operator);
- $providerNoEqualOp = str_replace('=', '', $provider->operator);
-
- $isEqualOp = '==' === $this->operator;
- $isNonEqualOp = '!=' === $this->operator;
- $isProviderEqualOp = '==' === $provider->operator;
- $isProviderNonEqualOp = '!=' === $provider->operator;
-
- // '!=' operator is match when other operator is not '==' operator or version is not match
- // these kinds of comparisons always have a solution
- if ($isNonEqualOp || $isProviderNonEqualOp) {
- return !$isEqualOp && !$isProviderEqualOp
- || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
- }
-
- // an example for the condition is <= 2.0 & < 1.0
- // these kinds of comparisons always have a solution
- if ($this->operator != '==' && $noEqualOp == $providerNoEqualOp) {
- return true;
- }
-
- if ($this->versionCompare($provider->version, $this->version, $this->operator, $compareBranches)) {
- // special case, e.g. require >= 1.0 and provide < 1.0
- // 1.0 >= 1.0 but 1.0 is outside of the provided interval
- if ($provider->version == $this->version && $provider->operator == $providerNoEqualOp && $this->operator != $noEqualOp) {
- return false;
- }
-
- return true;
- }
-
- return false;
- }
-
- public function __toString()
- {
- return $this->operator.' '.$this->version;
- }
}
diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php
index 60cff3b33..42398e41f 100644
--- a/src/Composer/Package/Loader/ArrayLoader.php
+++ b/src/Composer/Package/Loader/ArrayLoader.php
@@ -14,9 +14,10 @@ namespace Composer\Package\Loader;
use Composer\Package;
use Composer\Package\AliasPackage;
+use Composer\Package\Link;
use Composer\Package\RootAliasPackage;
use Composer\Package\RootPackageInterface;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
/**
* @author Konstantin Kudryashiv
@@ -115,7 +116,7 @@ class ArrayLoader implements LoaderInterface
if (isset($config[$type])) {
$method = 'set'.ucfirst($opts['method']);
$package->{$method}(
- $this->versionParser->parseLinks(
+ $this->parseLinks(
$package->getName(),
$package->getPrettyVersion(),
$opts['description'],
@@ -147,7 +148,7 @@ class ArrayLoader implements LoaderInterface
}
if (!empty($config['time'])) {
- $time = preg_match('/^\d+$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
+ $time = preg_match('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
try {
$date = new \DateTime($time, new \DateTimeZone('UTC'));
@@ -216,6 +217,29 @@ class ArrayLoader implements LoaderInterface
return $package;
}
+ /**
+ * @param string $source source package name
+ * @param string $sourceVersion source package version (pretty version ideally)
+ * @param string $description link description (e.g. requires, replaces, ..)
+ * @param array $links array of package name => constraint mappings
+ * @return Link[]
+ */
+ public function parseLinks($source, $sourceVersion, $description, $links)
+ {
+ $res = array();
+ foreach ($links as $target => $constraint) {
+ if ('self.version' === $constraint) {
+ $parsedConstraint = $this->versionParser->parseConstraints($sourceVersion);
+ } else {
+ $parsedConstraint = $this->versionParser->parseConstraints($constraint);
+ }
+
+ $res[strtolower($target)] = new Link($source, $target, $parsedConstraint, $description, $constraint);
+ }
+
+ return $res;
+ }
+
/**
* Retrieves a branch alias (dev-master => 1.0.x-dev for example) if it exists
*
diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php
index 9c7c436bc..1266346db 100644
--- a/src/Composer/Package/Loader/RootPackageLoader.php
+++ b/src/Composer/Package/Loader/RootPackageLoader.php
@@ -16,13 +16,10 @@ use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Config;
use Composer\Factory;
-use Composer\Package\Version\VersionParser;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Semver\VersionParser;
use Composer\Repository\RepositoryManager;
-use Composer\Repository\Vcs\HgDriver;
-use Composer\IO\NullIO;
use Composer\Util\ProcessExecutor;
-use Composer\Util\Git as GitUtil;
-use Composer\Util\Svn as SvnUtil;
/**
* ArrayLoader built for the sole purpose of loading the root package
@@ -33,16 +30,28 @@ use Composer\Util\Svn as SvnUtil;
*/
class RootPackageLoader extends ArrayLoader
{
+ /**
+ * @var RepositoryManager
+ */
private $manager;
- private $config;
- private $process;
- public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, ProcessExecutor $process = null)
+ /**
+ * @var Config
+ */
+ private $config;
+
+ /**
+ * @var VersionGuesser
+ */
+ private $versionGuesser;
+
+ public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null)
{
+ parent::__construct($parser);
+
$this->manager = $manager;
$this->config = $config;
- $this->process = $process ?: new ProcessExecutor();
- parent::__construct($parser);
+ $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor(), $this->versionParser);
}
public function load(array $config, $class = 'Composer\Package\RootPackage')
@@ -56,7 +65,7 @@ class RootPackageLoader extends ArrayLoader
if (getenv('COMPOSER_ROOT_VERSION')) {
$version = getenv('COMPOSER_ROOT_VERSION');
} else {
- $version = $this->guessVersion($config);
+ $version = $this->versionGuesser->guessVersion($config, getcwd());
}
if (!$version) {
@@ -176,172 +185,4 @@ class RootPackageLoader extends ArrayLoader
return $references;
}
-
- private function guessVersion(array $config)
- {
- if (function_exists('proc_open')) {
- $version = $this->guessGitVersion($config);
- if (null !== $version) {
- return $version;
- }
-
- $version = $this->guessHgVersion($config);
- if (null !== $version) {
- return $version;
- }
-
- return $this->guessSvnVersion($config);
- }
- }
-
- private function guessGitVersion(array $config)
- {
- GitUtil::cleanEnv();
-
- // try to fetch current version from git tags
- if (0 === $this->process->execute('git describe --exact-match --tags', $output)) {
- try {
- return $this->versionParser->normalize(trim($output));
- } catch (\Exception $e) {
- }
- }
-
- // try to fetch current version from git branch
- if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) {
- $branches = array();
- $isFeatureBranch = false;
- $version = null;
-
- // find current branch and collect all branch names
- foreach ($this->process->splitLines($output) as $branch) {
- if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
- if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') {
- $version = 'dev-'.$match[2];
- $isFeatureBranch = true;
- } else {
- $version = $this->versionParser->normalizeBranch($match[1]);
- $isFeatureBranch = 0 === strpos($version, 'dev-');
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$match[1];
- }
- }
- }
-
- if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
- if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
- $branches[] = $match[1];
- }
- }
- }
-
- if (!$isFeatureBranch) {
- return $version;
- }
-
- // try to find the best (nearest) version branch to assume this feature's version
- $version = $this->guessFeatureVersion($config, $version, $branches, 'git rev-list %candidate%..%branch%');
-
- return $version;
- }
- }
-
- private function guessHgVersion(array $config)
- {
- // try to fetch current version from hg branch
- if (0 === $this->process->execute('hg branch', $output)) {
- $branch = trim($output);
- $version = $this->versionParser->normalizeBranch($branch);
- $isFeatureBranch = 0 === strpos($version, 'dev-');
-
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$branch;
- }
-
- if (!$isFeatureBranch) {
- return $version;
- }
-
- // re-use the HgDriver to fetch branches (this properly includes bookmarks)
- $config = array('url' => getcwd());
- $driver = new HgDriver($config, new NullIO(), $this->config, $this->process);
- $branches = array_keys($driver->getBranches());
-
- // try to find the best (nearest) version branch to assume this feature's version
- $version = $this->guessFeatureVersion($config, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"');
-
- return $version;
- }
- }
-
- private function guessFeatureVersion(array $config, $version, array $branches, $scmCmdline)
- {
- // ignore feature branches if they have no branch-alias or self.version is used
- // and find the branch they came from to use as a version instead
- if ((isset($config['extra']['branch-alias']) && !isset($config['extra']['branch-alias'][$version]))
- || strpos(json_encode($config), '"self.version"')
- ) {
- $branch = preg_replace('{^dev-}', '', $version);
- $length = PHP_INT_MAX;
-
- $nonFeatureBranches = '';
- if (!empty($config['non-feature-branches'])) {
- $nonFeatureBranches = implode('|', $config['non-feature-branches']);
- }
-
- foreach ($branches as $candidate) {
- // return directly, if branch is configured to be non-feature branch
- if ($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) {
- return $version;
- }
-
- // do not compare against other feature branches
- if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) {
- continue;
- }
-
- $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
- if (0 !== $this->process->execute($cmdLine, $output)) {
- continue;
- }
-
- if (strlen($output) < $length) {
- $length = strlen($output);
- $version = $this->versionParser->normalizeBranch($candidate);
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$match[1];
- }
- }
- }
- }
-
- return $version;
- }
-
- private function guessSvnVersion(array $config)
- {
- SvnUtil::cleanEnv();
-
- // try to fetch current version from svn
- if (0 === $this->process->execute('svn info --xml', $output)) {
- $trunkPath = isset($config['trunk-path']) ? preg_quote($config['trunk-path'], '#') : 'trunk';
- $branchesPath = isset($config['branches-path']) ? preg_quote($config['branches-path'], '#') : 'branches';
- $tagsPath = isset($config['tags-path']) ? preg_quote($config['tags-path'], '#') : 'tags';
-
- $urlPattern = '#.*/('.$trunkPath.'|('.$branchesPath.'|'. $tagsPath .')/(.*))#';
-
- if (preg_match($urlPattern, $output, $matches)) {
- if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
- // we are in a branches path
- $version = $this->versionParser->normalizeBranch($matches[3]);
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$matches[3];
- }
-
- return $version;
- }
-
- return $this->versionParser->normalize(trim($matches[1]));
- }
- }
- }
}
diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php
index 86386989c..4f01a680d 100644
--- a/src/Composer/Package/Loader/ValidatingArrayLoader.php
+++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php
@@ -14,8 +14,8 @@ namespace Composer\Package\Loader;
use Composer\Package;
use Composer\Package\BasePackage;
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+use Composer\Semver\VersionParser;
use Composer\Repository\PlatformRepository;
/**
@@ -149,7 +149,7 @@ class ValidatingArrayLoader implements LoaderInterface
}
}
- $unboundConstraint = new VersionConstraint('=', $this->versionParser->normalize('dev-master'));
+ $unboundConstraint = new Constraint('=', $this->versionParser->normalize('dev-master'));
foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php
index 9f9a0abf8..dba5541be 100644
--- a/src/Composer/Package/Locker.php
+++ b/src/Composer/Package/Locker.php
@@ -19,9 +19,9 @@ use Composer\Util\ProcessExecutor;
use Composer\Repository\ArrayRepository;
use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\Loader\ArrayLoader;
-use Composer\Package\Version\VersionParser;
use Composer\Util\Git as GitUtil;
use Composer\IO\IOInterface;
+use Seld\JsonLint\ParsingException;
/**
* Reads/writes project lockfile (composer.lock).
@@ -35,6 +35,7 @@ class Locker
private $repositoryManager;
private $installationManager;
private $hash;
+ private $contentHash;
private $loader;
private $dumper;
private $process;
@@ -44,17 +45,18 @@ class Locker
* Initializes packages locker.
*
* @param IOInterface $io
- * @param JsonFile $lockFile lockfile loader
- * @param RepositoryManager $repositoryManager repository manager instance
- * @param InstallationManager $installationManager installation manager instance
- * @param string $hash unique hash of the current composer configuration
+ * @param JsonFile $lockFile lockfile loader
+ * @param RepositoryManager $repositoryManager repository manager instance
+ * @param InstallationManager $installationManager installation manager instance
+ * @param string $composerFileContents The contents of the composer file
*/
- public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $hash)
+ public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $composerFileContents)
{
$this->lockFile = $lockFile;
$this->repositoryManager = $repositoryManager;
$this->installationManager = $installationManager;
- $this->hash = $hash;
+ $this->hash = md5($composerFileContents);
+ $this->contentHash = $this->getContentHash($composerFileContents);
$this->loader = new ArrayLoader(null, true);
$this->dumper = new ArrayDumper();
$this->process = new ProcessExecutor($io);
@@ -85,6 +87,11 @@ class Locker
{
$lock = $this->lockFile->read();
+ if (!empty($lock['content-hash'])) {
+ // There is a content hash key, use that instead of the file hash
+ return $this->contentHash === $lock['content-hash'];
+ }
+
return $this->hash === $lock['hash'];
}
@@ -133,11 +140,10 @@ class Locker
public function getPlatformRequirements($withDevReqs = false)
{
$lockData = $this->getLockData();
- $versionParser = new VersionParser();
$requirements = array();
if (!empty($lockData['platform'])) {
- $requirements = $versionParser->parseLinks(
+ $requirements = $this->loader->parseLinks(
'__ROOT__',
'1.0.0',
'requires',
@@ -146,7 +152,7 @@ class Locker
}
if ($withDevReqs && !empty($lockData['platform-dev'])) {
- $devRequirements = $versionParser->parseLinks(
+ $devRequirements = $this->loader->parseLinks(
'__ROOT__',
'1.0.0',
'requires',
@@ -239,8 +245,9 @@ class Locker
$lock = array(
'_readme' => array('This file locks the dependencies of your project to a known state',
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
- 'This file is @gener'.'ated automatically'),
+ 'This file is @gener'.'ated automatically', ),
'hash' => $this->hash,
+ 'content-hash' => $this->contentHash,
'packages' => null,
'packages-dev' => null,
'aliases' => array(),
@@ -280,7 +287,12 @@ class Locker
return false;
}
- if (!$this->isLocked() || $lock !== $this->getLockData()) {
+ try {
+ $isLocked = $this->isLocked();
+ } catch (ParsingException $e) {
+ $isLocked = false;
+ }
+ if (!$isLocked || $lock !== $this->getLockData()) {
$this->lockFile->write($lock);
$this->lockDataCache = null;
@@ -378,4 +390,43 @@ class Locker
return $datetime ? $datetime->format('Y-m-d H:i:s') : null;
}
+
+ /**
+ * Returns the md5 hash of the sorted content of the composer file.
+ *
+ * @param string $composerFileContents The contents of the composer file.
+ *
+ * @return string
+ */
+ private function getContentHash($composerFileContents)
+ {
+ $content = json_decode($composerFileContents, true);
+
+ $relevantKeys = array(
+ 'name',
+ 'version',
+ 'require',
+ 'require-dev',
+ 'conflict',
+ 'replace',
+ 'provide',
+ 'minimum-stability',
+ 'prefer-stable',
+ 'repositories',
+ 'extra',
+ );
+
+ $relevantContent = array();
+
+ foreach (array_intersect($relevantKeys, array_keys($content)) as $key) {
+ $relevantContent[$key] = $content[$key];
+ }
+ if (isset($content['config']['platform'])) {
+ $relevantContent['config']['platform'] = $content['config']['platform'];
+ }
+
+ ksort($relevantContent);
+
+ return md5(json_encode($relevantContent));
+ }
}
diff --git a/src/Composer/Package/Package.php b/src/Composer/Package/Package.php
index 0c98a0e56..7f813887e 100644
--- a/src/Composer/Package/Package.php
+++ b/src/Composer/Package/Package.php
@@ -12,7 +12,7 @@
namespace Composer\Package;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Util\ComposerMirror;
/**
diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php
index a51274d5b..c88771cfd 100644
--- a/src/Composer/Package/PackageInterface.php
+++ b/src/Composer/Package/PackageInterface.php
@@ -192,6 +192,16 @@ interface PackageInterface
*/
public function getPrettyVersion();
+ /**
+ * Returns the pretty version string plus a git or hg commit hash of this package
+ *
+ * @see getPrettyVersion
+ *
+ * @param bool $truncate If the source reference is a sha1 hash, truncate it
+ * @return string version
+ */
+ public function getFullPrettyVersion($truncate = true);
+
/**
* Returns the release date of the package
*
diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php
new file mode 100644
index 000000000..4dd0be511
--- /dev/null
+++ b/src/Composer/Package/Version/VersionGuesser.php
@@ -0,0 +1,228 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Package\Version;
+
+use Composer\Config;
+use Composer\Repository\Vcs\HgDriver;
+use Composer\IO\NullIO;
+use Composer\Semver\VersionParser as SemverVersionParser;
+use Composer\Util\Git as GitUtil;
+use Composer\Util\ProcessExecutor;
+use Composer\Util\Svn as SvnUtil;
+
+/**
+ * Try to guess the current version number based on different VCS configuration.
+ *
+ * @author Jordi Boggiano
+ * @author Samuel Roze
+ */
+class VersionGuesser
+{
+ /**
+ * @var Config
+ */
+ private $config;
+
+ /**
+ * @var ProcessExecutor
+ */
+ private $process;
+
+ /**
+ * @var SemverVersionParser
+ */
+ private $versionParser;
+
+ /**
+ * @param Config $config
+ * @param ProcessExecutor $process
+ * @param VersionParser $versionParser
+ */
+ public function __construct(Config $config, ProcessExecutor $process, SemverVersionParser $versionParser)
+ {
+ $this->config = $config;
+ $this->process = $process;
+ $this->versionParser = $versionParser;
+ }
+
+ /**
+ * @param array $packageConfig
+ * @param string $path Path to guess into
+ */
+ public function guessVersion(array $packageConfig, $path)
+ {
+ if (function_exists('proc_open')) {
+ $version = $this->guessGitVersion($packageConfig, $path);
+ if (null !== $version) {
+ return $version;
+ }
+
+ $version = $this->guessHgVersion($packageConfig, $path);
+ if (null !== $version) {
+ return $version;
+ }
+
+ return $this->guessSvnVersion($packageConfig, $path);
+ }
+ }
+
+ private function guessGitVersion(array $packageConfig, $path)
+ {
+ GitUtil::cleanEnv();
+
+ // try to fetch current version from git tags
+ if (0 === $this->process->execute('git describe --exact-match --tags', $output, $path)) {
+ try {
+ return $this->versionParser->normalize(trim($output));
+ } catch (\Exception $e) {
+ }
+ }
+
+ // try to fetch current version from git branch
+ if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output, $path)) {
+ $branches = array();
+ $isFeatureBranch = false;
+ $version = null;
+
+ // find current branch and collect all branch names
+ foreach ($this->process->splitLines($output) as $branch) {
+ if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
+ if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') {
+ $version = 'dev-'.$match[2];
+ $isFeatureBranch = true;
+ } else {
+ $version = $this->versionParser->normalizeBranch($match[1]);
+ $isFeatureBranch = 0 === strpos($version, 'dev-');
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$match[1];
+ }
+ }
+ }
+
+ if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
+ if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
+ $branches[] = $match[1];
+ }
+ }
+ }
+
+ if (!$isFeatureBranch) {
+ return $version;
+ }
+
+ // try to find the best (nearest) version branch to assume this feature's version
+ $version = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path);
+
+ return $version;
+ }
+ }
+
+ private function guessHgVersion(array $packageConfig, $path)
+ {
+ // try to fetch current version from hg branch
+ if (0 === $this->process->execute('hg branch', $output, $path)) {
+ $branch = trim($output);
+ $version = $this->versionParser->normalizeBranch($branch);
+ $isFeatureBranch = 0 === strpos($version, 'dev-');
+
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$branch;
+ }
+
+ if (!$isFeatureBranch) {
+ return $version;
+ }
+
+ // re-use the HgDriver to fetch branches (this properly includes bookmarks)
+ $driver = new HgDriver(array('url' => $path), new NullIO(), $this->config, $this->process);
+ $branches = array_keys($driver->getBranches());
+
+ // try to find the best (nearest) version branch to assume this feature's version
+ $version = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path);
+
+ return $version;
+ }
+ }
+
+ private function guessFeatureVersion(array $packageConfig, $version, array $branches, $scmCmdline, $path)
+ {
+ // ignore feature branches if they have no branch-alias or self.version is used
+ // and find the branch they came from to use as a version instead
+ if ((isset($packageConfig['extra']['branch-alias']) && !isset($packageConfig['extra']['branch-alias'][$version]))
+ || strpos(json_encode($packageConfig), '"self.version"')
+ ) {
+ $branch = preg_replace('{^dev-}', '', $version);
+ $length = PHP_INT_MAX;
+
+ $nonFeatureBranches = '';
+ if (!empty($packageConfig['non-feature-branches'])) {
+ $nonFeatureBranches = implode('|', $packageConfig['non-feature-branches']);
+ }
+
+ foreach ($branches as $candidate) {
+ // return directly, if branch is configured to be non-feature branch
+ if ($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) {
+ return $version;
+ }
+
+ // do not compare against other feature branches
+ if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) {
+ continue;
+ }
+
+ $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
+ if (0 !== $this->process->execute($cmdLine, $output, $path)) {
+ continue;
+ }
+
+ if (strlen($output) < $length) {
+ $length = strlen($output);
+ $version = $this->versionParser->normalizeBranch($candidate);
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$match[1];
+ }
+ }
+ }
+ }
+
+ return $version;
+ }
+
+ private function guessSvnVersion(array $packageConfig, $path)
+ {
+ SvnUtil::cleanEnv();
+
+ // try to fetch current version from svn
+ if (0 === $this->process->execute('svn info --xml', $output, $path)) {
+ $trunkPath = isset($packageConfig['trunk-path']) ? preg_quote($packageConfig['trunk-path'], '#') : 'trunk';
+ $branchesPath = isset($packageConfig['branches-path']) ? preg_quote($packageConfig['branches-path'], '#') : 'branches';
+ $tagsPath = isset($packageConfig['tags-path']) ? preg_quote($packageConfig['tags-path'], '#') : 'tags';
+
+ $urlPattern = '#.*/('.$trunkPath.'|('.$branchesPath.'|'. $tagsPath .')/(.*))#';
+
+ if (preg_match($urlPattern, $output, $matches)) {
+ if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
+ // we are in a branches path
+ $version = $this->versionParser->normalizeBranch($matches[3]);
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$matches[3];
+ }
+
+ return $version;
+ }
+
+ return $this->versionParser->normalize(trim($matches[1]));
+ }
+ }
+ }
+}
diff --git a/src/Composer/Package/Version/VersionParser.php b/src/Composer/Package/Version/VersionParser.php
index b5a32a448..00d1e669a 100644
--- a/src/Composer/Package/Version/VersionParser.php
+++ b/src/Composer/Package/Version/VersionParser.php
@@ -12,513 +12,18 @@
namespace Composer\Package\Version;
-use Composer\Package\BasePackage;
-use Composer\Package\PackageInterface;
-use Composer\Package\Link;
-use Composer\Package\LinkConstraint\EmptyConstraint;
-use Composer\Package\LinkConstraint\MultiConstraint;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\VersionParser as SemverVersionParser;
-/**
- * Version parser
- *
- * @author Jordi Boggiano
- */
-class VersionParser
+class VersionParser extends SemverVersionParser
{
- private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';
-
/**
- * Returns the stability of a version
+ * Parses an array of strings representing package/version pairs.
*
- * @param string $version
- * @return string
- */
- public static function parseStability($version)
- {
- $version = preg_replace('{#.+$}i', '', $version);
-
- if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) {
- return 'dev';
- }
-
- preg_match('{'.self::$modifierRegex.'$}i', strtolower($version), $match);
- if (!empty($match[3])) {
- return 'dev';
- }
-
- if (!empty($match[1])) {
- if ('beta' === $match[1] || 'b' === $match[1]) {
- return 'beta';
- }
- if ('alpha' === $match[1] || 'a' === $match[1]) {
- return 'alpha';
- }
- if ('rc' === $match[1]) {
- return 'RC';
- }
- }
-
- return 'stable';
- }
-
- public static function normalizeStability($stability)
- {
- $stability = strtolower($stability);
-
- return $stability === 'rc' ? 'RC' : $stability;
- }
-
- public static function formatVersion(PackageInterface $package, $truncate = true)
- {
- if (!$package->isDev() || !in_array($package->getSourceType(), array('hg', 'git'))) {
- return $package->getPrettyVersion();
- }
-
- // if source reference is a sha1 hash -- truncate
- if ($truncate && strlen($package->getSourceReference()) === 40) {
- return $package->getPrettyVersion() . ' ' . substr($package->getSourceReference(), 0, 7);
- }
-
- return $package->getPrettyVersion() . ' ' . $package->getSourceReference();
- }
-
- /**
- * Normalizes a version string to be able to perform comparisons on it
+ * The parsing results in an array of arrays, each of which
+ * contain a 'name' key with value and optionally a 'version' key with value.
*
- * @param string $version
- * @param string $fullVersion optional complete version string to give more context
- * @throws \UnexpectedValueException
- * @return string
- */
- public function normalize($version, $fullVersion = null)
- {
- $version = trim($version);
- if (null === $fullVersion) {
- $fullVersion = $version;
- }
-
- // ignore aliases and just assume the alias is required instead of the source
- if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) {
- $version = $match[1];
- }
-
- // ignore build metadata
- if (preg_match('{^([^,\s+]+)\+[^\s]+$}', $version, $match)) {
- $version = $match[1];
- }
-
- // match master-like branches
- if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
- return '9999999-dev';
- }
-
- if ('dev-' === strtolower(substr($version, 0, 4))) {
- return 'dev-'.substr($version, 4);
- }
-
- // match classical versioning
- if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?'.self::$modifierRegex.'$}i', $version, $matches)) {
- $version = $matches[1]
- .(!empty($matches[2]) ? $matches[2] : '.0')
- .(!empty($matches[3]) ? $matches[3] : '.0')
- .(!empty($matches[4]) ? $matches[4] : '.0');
- $index = 5;
- } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)'.self::$modifierRegex.'$}i', $version, $matches)) { // match date-based versioning
- $version = preg_replace('{\D}', '-', $matches[1]);
- $index = 2;
- } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?'.self::$modifierRegex.'$}i', $version, $matches)) {
- $version = $matches[1]
- .(!empty($matches[2]) ? $matches[2] : '.0')
- .(!empty($matches[3]) ? $matches[3] : '.0')
- .(!empty($matches[4]) ? $matches[4] : '.0');
- $index = 5;
- }
-
- // add version modifiers if a version was matched
- if (isset($index)) {
- if (!empty($matches[$index])) {
- if ('stable' === $matches[$index]) {
- return $version;
- }
- $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index+1]) ? $matches[$index+1] : '');
- }
-
- if (!empty($matches[$index+2])) {
- $version .= '-dev';
- }
-
- return $version;
- }
-
- // match dev branches
- if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
- try {
- return $this->normalizeBranch($match[1]);
- } catch (\Exception $e) {
- }
- }
-
- $extraMessage = '';
- if (preg_match('{ +as +'.preg_quote($version).'$}', $fullVersion)) {
- $extraMessage = ' in "'.$fullVersion.'", the alias must be an exact version';
- } elseif (preg_match('{^'.preg_quote($version).' +as +}', $fullVersion)) {
- $extraMessage = ' in "'.$fullVersion.'", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
- }
-
- throw new \UnexpectedValueException('Invalid version string "'.$version.'"'.$extraMessage);
- }
-
- /**
- * Extract numeric prefix from alias, if it is in numeric format, suitable for
- * version comparison
+ * @param array $pairs a set of package/version pairs separated by ":", "=" or " "
*
- * @param string $branch Branch name (e.g. 2.1.x-dev)
- * @return string|false Numeric prefix if present (e.g. 2.1.) or false
- */
- public function parseNumericAliasPrefix($branch)
- {
- if (preg_match('/^(?P(\d+\\.)*\d+)(?:\.x)?-dev$/i', $branch, $matches)) {
- return $matches['version'].".";
- }
-
- return false;
- }
-
- /**
- * Normalizes a branch name to be able to perform comparisons on it
- *
- * @param string $name
- * @return string
- */
- public function normalizeBranch($name)
- {
- $name = trim($name);
-
- if (in_array($name, array('master', 'trunk', 'default'))) {
- return $this->normalize($name);
- }
-
- if (preg_match('#^v?(\d+)(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?$#i', $name, $matches)) {
- $version = '';
- for ($i = 1; $i < 5; $i++) {
- $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
- }
-
- return str_replace('x', '9999999', $version).'-dev';
- }
-
- return 'dev-'.$name;
- }
-
- /**
- * @param string $source source package name
- * @param string $sourceVersion source package version (pretty version ideally)
- * @param string $description link description (e.g. requires, replaces, ..)
- * @param array $links array of package name => constraint mappings
- * @return Link[]
- */
- public function parseLinks($source, $sourceVersion, $description, $links)
- {
- $res = array();
- foreach ($links as $target => $constraint) {
- if ('self.version' === $constraint) {
- $parsedConstraint = $this->parseConstraints($sourceVersion);
- } else {
- $parsedConstraint = $this->parseConstraints($constraint);
- }
-
- $res[strtolower($target)] = new Link($source, $target, $parsedConstraint, $description, $constraint);
- }
-
- return $res;
- }
-
- /**
- * Parses as constraint string into LinkConstraint objects
- *
- * @param string $constraints
- * @return \Composer\Package\LinkConstraint\LinkConstraintInterface
- */
- public function parseConstraints($constraints)
- {
- $prettyConstraint = $constraints;
-
- if (preg_match('{^([^,\s]*?)@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $constraints, $match)) {
- $constraints = empty($match[1]) ? '*' : $match[1];
- }
-
- if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
- $constraints = $match[1];
- }
-
- $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
- $orGroups = array();
- foreach ($orConstraints as $constraints) {
- $andConstraints = preg_split('{(?< ,]) *(? 1) {
- $constraintObjects = array();
- foreach ($andConstraints as $constraint) {
- $constraintObjects = array_merge($constraintObjects, $this->parseConstraint($constraint));
- }
- } else {
- $constraintObjects = $this->parseConstraint($andConstraints[0]);
- }
-
- if (1 === count($constraintObjects)) {
- $constraint = $constraintObjects[0];
- } else {
- $constraint = new MultiConstraint($constraintObjects);
- }
-
- $orGroups[] = $constraint;
- }
-
- if (1 === count($orGroups)) {
- $constraint = $orGroups[0];
- } else {
- $constraint = new MultiConstraint($orGroups, false);
- }
-
- $constraint->setPrettyString($prettyConstraint);
-
- return $constraint;
- }
-
- private function parseConstraint($constraint)
- {
- if (preg_match('{^([^,\s]+?)@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $constraint, $match)) {
- $constraint = $match[1];
- if ($match[2] !== 'stable') {
- $stabilityModifier = $match[2];
- }
- }
-
- if (preg_match('{^[xX*](\.[xX*])*$}i', $constraint)) {
- return array(new EmptyConstraint);
- }
-
- $versionRegex = '(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?'.self::$modifierRegex;
-
- // match tilde constraints
- // like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
- // version, to ensure that unstable instances of the current version are allowed.
- // however, if a stability suffix is added to the constraint, then a >= match on the current version is
- // used instead
- if (preg_match('{^~>?'.$versionRegex.'$}i', $constraint, $matches)) {
- if (substr($constraint, 0, 2) === '~>') {
- throw new \UnexpectedValueException(
- 'Could not parse version constraint '.$constraint.': '.
- 'Invalid operator "~>", you probably meant to use the "~" operator'
- );
- }
-
- // Work out which position in the version we are operating at
- if (isset($matches[4]) && '' !== $matches[4]) {
- $position = 4;
- } elseif (isset($matches[3]) && '' !== $matches[3]) {
- $position = 3;
- } elseif (isset($matches[2]) && '' !== $matches[2]) {
- $position = 2;
- } else {
- $position = 1;
- }
-
- // Calculate the stability suffix
- $stabilitySuffix = '';
- if (!empty($matches[5])) {
- $stabilitySuffix .= '-' . $this->expandStability($matches[5]) . (!empty($matches[6]) ? $matches[6] : '');
- }
-
- if (!empty($matches[7])) {
- $stabilitySuffix .= '-dev';
- }
-
- if (!$stabilitySuffix) {
- $stabilitySuffix = "-dev";
- }
- $lowVersion = $this->manipulateVersionString($matches, $position, 0) . $stabilitySuffix;
- $lowerBound = new VersionConstraint('>=', $lowVersion);
-
- // For upper bound, we increment the position of one more significance,
- // but highPosition = 0 would be illegal
- $highPosition = max(1, $position - 1);
- $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
- $upperBound = new VersionConstraint('<', $highVersion);
-
- return array(
- $lowerBound,
- $upperBound
- );
- }
-
- // match caret constraints
- if (preg_match('{^\^'.$versionRegex.'($)}i', $constraint, $matches)) {
- // Work out which position in the version we are operating at
- if ('0' !== $matches[1] || '' === $matches[2]) {
- $position = 1;
- } elseif ('0' !== $matches[2] || '' === $matches[3]) {
- $position = 2;
- } else {
- $position = 3;
- }
-
- // Calculate the stability suffix
- $stabilitySuffix = '';
- if (empty($matches[5]) && empty($matches[7])) {
- $stabilitySuffix .= '-dev';
- }
-
- $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
- $lowerBound = new VersionConstraint('>=', $lowVersion);
-
- // For upper bound, we increment the position of one more significance,
- // but highPosition = 0 would be illegal
- $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
- $upperBound = new VersionConstraint('<', $highVersion);
-
- return array(
- $lowerBound,
- $upperBound
- );
- }
-
- // match wildcard constraints
- if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', $constraint, $matches)) {
- if (isset($matches[3]) && '' !== $matches[3]) {
- $position = 3;
- } elseif (isset($matches[2]) && '' !== $matches[2]) {
- $position = 2;
- } else {
- $position = 1;
- }
-
- $lowVersion = $this->manipulateVersionString($matches, $position) . "-dev";
- $highVersion = $this->manipulateVersionString($matches, $position, 1) . "-dev";
-
- if ($lowVersion === "0.0.0.0-dev") {
- return array(new VersionConstraint('<', $highVersion));
- }
-
- return array(
- new VersionConstraint('>=', $lowVersion),
- new VersionConstraint('<', $highVersion),
- );
- }
-
- // match hyphen constraints
- if (preg_match('{^(?P'.$versionRegex.') +- +(?P'.$versionRegex.')($)}i', $constraint, $matches)) {
- // Calculate the stability suffix
- $lowStabilitySuffix = '';
- if (empty($matches[6]) && empty($matches[8])) {
- $lowStabilitySuffix = '-dev';
- }
-
- $lowVersion = $this->normalize($matches['from']);
- $lowerBound = new VersionConstraint('>=', $lowVersion . $lowStabilitySuffix);
-
- $empty = function ($x) {
- return ($x === 0 || $x === "0") ? false : empty($x);
- };
-
- if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
- $highVersion = $this->normalize($matches['to']);
- $upperBound = new VersionConstraint('<=', $highVersion);
- } else {
- $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
- $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
- $upperBound = new VersionConstraint('<', $highVersion);
- }
-
- return array(
- $lowerBound,
- $upperBound
- );
- }
-
- // match operators constraints
- if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
- try {
- $version = $this->normalize($matches[2]);
-
- if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') {
- $version .= '-' . $stabilityModifier;
- } elseif ('<' === $matches[1]) {
- if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
- $version .= '-dev';
- }
- }
-
- return array(new VersionConstraint($matches[1] ?: '=', $version));
- } catch (\Exception $e) {
- }
- }
-
- $message = 'Could not parse version constraint '.$constraint;
- if (isset($e)) {
- $message .= ': '. $e->getMessage();
- }
-
- throw new \UnexpectedValueException($message);
- }
-
- /**
- * Increment, decrement, or simply pad a version number.
- *
- * Support function for {@link parseConstraint()}
- *
- * @param array $matches Array with version parts in array indexes 1,2,3,4
- * @param int $position 1,2,3,4 - which segment of the version to decrement
- * @param int $increment
- * @param string $pad The string to pad version parts after $position
- * @return string The new version
- */
- private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
- {
- for ($i = 4; $i > 0; $i--) {
- if ($i > $position) {
- $matches[$i] = $pad;
- } elseif ($i == $position && $increment) {
- $matches[$i] += $increment;
- // If $matches[$i] was 0, carry the decrement
- if ($matches[$i] < 0) {
- $matches[$i] = $pad;
- $position--;
-
- // Return null on a carry overflow
- if ($i == 1) {
- return;
- }
- }
- }
- }
-
- return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
- }
-
- private function expandStability($stability)
- {
- $stability = strtolower($stability);
-
- switch ($stability) {
- case 'a':
- return 'alpha';
- case 'b':
- return 'beta';
- case 'p':
- case 'pl':
- return 'patch';
- case 'rc':
- return 'RC';
- default:
- return $stability;
- }
- }
-
- /**
- * Parses a name/version pairs and returns an array of pairs + the
- *
- * @param array $pairs a set of package/version pairs separated by ":", "=" or " "
* @return array[] array of arrays containing a name and (if provided) a version
*/
public function parseNameVersionPairs(array $pairs)
@@ -528,8 +33,8 @@ class VersionParser
for ($i = 0, $count = count($pairs); $i < $count; $i++) {
$pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i]));
- if (false === strpos($pair, ' ') && isset($pairs[$i+1]) && false === strpos($pairs[$i+1], '/')) {
- $pair .= ' '.$pairs[$i+1];
+ if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false === strpos($pairs[$i + 1], '/')) {
+ $pair .= ' '.$pairs[$i + 1];
$i++;
}
diff --git a/src/Composer/Package/Version/VersionSelector.php b/src/Composer/Package/Version/VersionSelector.php
index 563ba056a..a22cf2c70 100644
--- a/src/Composer/Package/Version/VersionSelector.php
+++ b/src/Composer/Package/Version/VersionSelector.php
@@ -16,6 +16,7 @@ use Composer\DependencyResolver\Pool;
use Composer\Package\PackageInterface;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Dumper\ArrayDumper;
+use Composer\Semver\VersionParser as SemverVersionParser;
/**
* Selects the best possible version for a package
@@ -130,7 +131,7 @@ class VersionSelector
private function getParser()
{
if ($this->parser === null) {
- $this->parser = new VersionParser();
+ $this->parser = new SemverVersionParser();
}
return $this->parser;
diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php
index 833b3e29b..174055f4e 100644
--- a/src/Composer/Plugin/PluginManager.php
+++ b/src/Composer/Plugin/PluginManager.php
@@ -16,12 +16,12 @@ use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Package\Package;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Repository\RepositoryInterface;
use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface;
use Composer\Package\Link;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
use Composer\DependencyResolver\Pool;
/**
@@ -45,9 +45,9 @@ class PluginManager
/**
* Initializes plugin manager
*
- * @param IOInterface $io
- * @param Composer $composer
- * @param Composer $globalComposer
+ * @param IOInterface $io
+ * @param Composer $composer
+ * @param Composer $globalComposer
*/
public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null)
{
@@ -131,7 +131,7 @@ class PluginManager
}
$currentPluginApiVersion = $this->getPluginApiVersion();
- $currentPluginApiConstraint = new VersionConstraint('==', $this->versionParser->normalize($currentPluginApiVersion));
+ $currentPluginApiConstraint = new Constraint('==', $this->versionParser->normalize($currentPluginApiVersion));
if (!$requiresComposer->matches($currentPluginApiConstraint)) {
$this->io->writeError('The "' . $package->getName() . '" plugin was skipped because it requires a Plugin API version ("' . $requiresComposer->getPrettyString() . '") that does not match your Composer installation ("' . $currentPluginApiVersion . '"). You may need to run composer update with the "--no-plugins" option.');
diff --git a/src/Composer/Repository/ArrayRepository.php b/src/Composer/Repository/ArrayRepository.php
index 4f6e2daa7..5f9eaf406 100644
--- a/src/Composer/Repository/ArrayRepository.php
+++ b/src/Composer/Repository/ArrayRepository.php
@@ -15,9 +15,9 @@ namespace Composer\Repository;
use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface;
use Composer\Package\CompletePackageInterface;
-use Composer\Package\Version\VersionParser;
-use Composer\Package\LinkConstraint\LinkConstraintInterface;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\ConstraintInterface;
+use Composer\Semver\Constraint\Constraint;
/**
* A repository implementation that simply stores packages in an array
@@ -26,6 +26,7 @@ use Composer\Package\LinkConstraint\VersionConstraint;
*/
class ArrayRepository implements RepositoryInterface
{
+ /** @var PackageInterface[] */
protected $packages;
public function __construct(array $packages = array())
@@ -42,14 +43,14 @@ class ArrayRepository implements RepositoryInterface
{
$name = strtolower($name);
- if (!$constraint instanceof LinkConstraintInterface) {
+ if (!$constraint instanceof ConstraintInterface) {
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($constraint);
}
foreach ($this->getPackages() as $package) {
if ($name === $package->getName()) {
- $pkgConstraint = new VersionConstraint('==', $package->getVersion());
+ $pkgConstraint = new Constraint('==', $package->getVersion());
if ($constraint->matches($pkgConstraint)) {
return $package;
}
@@ -66,14 +67,14 @@ class ArrayRepository implements RepositoryInterface
$name = strtolower($name);
$packages = array();
- if (null !== $constraint && !$constraint instanceof LinkConstraintInterface) {
+ if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($constraint);
}
foreach ($this->getPackages() as $package) {
if ($name === $package->getName()) {
- $pkgConstraint = new VersionConstraint('==', $package->getVersion());
+ $pkgConstraint = new Constraint('==', $package->getVersion());
if (null === $constraint || $constraint->matches($pkgConstraint)) {
$packages[] = $package;
}
diff --git a/src/Composer/Repository/ArtifactRepository.php b/src/Composer/Repository/ArtifactRepository.php
index 2bb518b8f..01d662212 100644
--- a/src/Composer/Repository/ArtifactRepository.php
+++ b/src/Composer/Repository/ArtifactRepository.php
@@ -15,6 +15,7 @@ namespace Composer\Repository;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Package\Loader\ArrayLoader;
+use Composer\Package\Loader\LoaderInterface;
/**
* @author Serge Smertin
@@ -48,7 +49,7 @@ class ArtifactRepository extends ArrayRepository
{
$io = $this->io;
- $directory = new \RecursiveDirectoryIterator($path);
+ $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($directory);
$regex = new \RegexIterator($iterator, '/^.+\.(zip|phar)$/i');
foreach ($regex as $file) {
@@ -77,7 +78,7 @@ class ArtifactRepository extends ArrayRepository
/**
* Find a file by name, returning the one that has the shortest path.
*
- * @param \ZipArchive $zip
+ * @param \ZipArchive $zip
* @param $filename
* @return bool|int
*/
@@ -140,7 +141,7 @@ class ArtifactRepository extends ArrayRepository
$package['dist'] = array(
'type' => 'zip',
'url' => $file->getPathname(),
- 'shasum' => sha1_file($file->getRealPath())
+ 'shasum' => sha1_file($file->getRealPath()),
);
$package = $this->loader->load($package);
diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php
index 1d3c2cd92..ce73037a8 100644
--- a/src/Composer/Repository/ComposerRepository.php
+++ b/src/Composer/Repository/ComposerRepository.php
@@ -13,10 +13,9 @@
namespace Composer\Repository;
use Composer\Package\Loader\ArrayLoader;
-use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\DependencyResolver\Pool;
use Composer\Json\JsonFile;
use Composer\Cache;
@@ -26,8 +25,8 @@ use Composer\Util\RemoteFilesystem;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\EventDispatcher\EventDispatcher;
-use Composer\Package\LinkConstraint\LinkConstraintInterface;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\ConstraintInterface;
+use Composer\Semver\Constraint\Constraint;
/**
* @author Jordi Boggiano
@@ -108,7 +107,7 @@ class ComposerRepository extends ArrayRepository
}
$name = strtolower($name);
- if (!$constraint instanceof LinkConstraintInterface) {
+ if (!$constraint instanceof ConstraintInterface) {
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($constraint);
}
@@ -118,7 +117,7 @@ class ComposerRepository extends ArrayRepository
$packages = $this->whatProvides(new Pool('dev'), $providerName);
foreach ($packages as $package) {
if ($name === $package->getName()) {
- $pkgConstraint = new VersionConstraint('==', $package->getVersion());
+ $pkgConstraint = new Constraint('==', $package->getVersion());
if ($constraint->matches($pkgConstraint)) {
return $package;
}
@@ -139,7 +138,7 @@ class ComposerRepository extends ArrayRepository
// normalize name
$name = strtolower($name);
- if (null !== $constraint && !$constraint instanceof LinkConstraintInterface) {
+ if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($constraint);
}
@@ -151,7 +150,7 @@ class ComposerRepository extends ArrayRepository
$candidates = $this->whatProvides(new Pool('dev'), $providerName);
foreach ($candidates as $package) {
if ($name === $package->getName()) {
- $pkgConstraint = new VersionConstraint('==', $package->getVersion());
+ $pkgConstraint = new Constraint('==', $package->getVersion());
if (null === $constraint || $constraint->matches($pkgConstraint)) {
$packages[] = $package;
}
@@ -585,6 +584,11 @@ class ComposerRepository extends ArrayRepository
$filename = $this->baseUrl.'/'.$filename;
}
+ // url-encode $ signs in URLs as bad proxies choke on them
+ if (($pos = strpos($filename, '$')) && preg_match('{^https?://.*}i', $filename)) {
+ $filename = substr($filename, 0, $pos) . '%24' . substr($filename, $pos + 1);
+ }
+
$retries = 3;
while ($retries--) {
try {
diff --git a/src/Composer/Repository/CompositeRepository.php b/src/Composer/Repository/CompositeRepository.php
index d05259f88..7f29385bf 100644
--- a/src/Composer/Repository/CompositeRepository.php
+++ b/src/Composer/Repository/CompositeRepository.php
@@ -108,20 +108,6 @@ class CompositeRepository implements RepositoryInterface
return $matches ? call_user_func_array('array_merge', $matches) : array();
}
- /**
- * {@inheritDoc}
- */
- public function filterPackages($callback, $class = 'Composer\Package\Package')
- {
- foreach ($this->repositories as $repository) {
- if (false === $repository->filterPackages($callback, $class)) {
- return false;
- }
- }
-
- return true;
- }
-
/**
* {@inheritdoc}
*/
diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php
new file mode 100644
index 000000000..294a7a187
--- /dev/null
+++ b/src/Composer/Repository/PathRepository.php
@@ -0,0 +1,144 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+use Composer\Config;
+use Composer\IO\IOInterface;
+use Composer\Json\JsonFile;
+use Composer\Package\Loader\ArrayLoader;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Semver\VersionParser;
+use Composer\Util\ProcessExecutor;
+
+/**
+ * This repository allows installing local packages that are not necessarily under their own VCS.
+ *
+ * The local packages will be symlinked when possible, else they will be copied.
+ *
+ * @code
+ * "require": {
+ * "/": "*"
+ * },
+ * "repositories": [
+ * {
+ * "type": "path",
+ * "url": "../../relative/path/to/package/"
+ * },
+ * {
+ * "type": "path",
+ * "url": "/absolute/path/to/package/"
+ * },
+ * {
+ * "type": "path",
+ * "url": "/absolute/path/to/several/packages/*"
+ * }
+ * ]
+ * @endcode
+ *
+ * @author Samuel Roze
+ * @author Johann Reinke
+ */
+class PathRepository extends ArrayRepository
+{
+ /**
+ * @var ArrayLoader
+ */
+ private $loader;
+
+ /**
+ * @var VersionGuesser
+ */
+ private $versionGuesser;
+
+ /**
+ * @var string
+ */
+ private $url;
+
+ /**
+ * @var ProcessExecutor
+ */
+ private $process;
+
+ /**
+ * Initializes path repository.
+ *
+ * @param array $repoConfig
+ * @param IOInterface $io
+ * @param Config $config
+ */
+ public function __construct(array $repoConfig, IOInterface $io, Config $config)
+ {
+ if (!isset($repoConfig['url'])) {
+ throw new \RuntimeException('You must specify the `url` configuration for the path repository');
+ }
+
+ $this->loader = new ArrayLoader();
+ $this->url = $repoConfig['url'];
+ $this->process = new ProcessExecutor($io);
+ $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser());
+
+ parent::__construct();
+ }
+
+ /**
+ * Initializes path repository.
+ *
+ * This method will basically read the folder and add the found package.
+ */
+ protected function initialize()
+ {
+ parent::initialize();
+
+ foreach ($this->getUrlMatches() as $url) {
+ $path = realpath($url) . '/';
+ $composerFilePath = $path.'composer.json';
+
+ if (!file_exists($composerFilePath)) {
+ continue;
+ }
+
+ $json = file_get_contents($composerFilePath);
+ $package = JsonFile::parseJson($json, $composerFilePath);
+ $package['dist'] = array(
+ 'type' => 'path',
+ 'url' => $url,
+ 'reference' => '',
+ );
+
+ if (!isset($package['version'])) {
+ $package['version'] = $this->versionGuesser->guessVersion($package, $path) ?: 'dev-master';
+ }
+ if (is_dir($path.'/.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) {
+ $package['dist']['reference'] = trim($output);
+ }
+
+ $package = $this->loader->load($package);
+ $this->addPackage($package);
+ }
+
+ if (count($this->getPackages()) == 0) {
+ throw new \RuntimeException(sprintf('No `composer.json` file found in any path repository in "%s"', $this->url));
+ }
+ }
+
+ /**
+ * Get a list of all (possibly relative) path names matching given url (supports globbing).
+ *
+ * @return string[]
+ */
+ private function getUrlMatches()
+ {
+ return glob($this->url, GLOB_MARK | GLOB_ONLYDIR);
+ }
+}
diff --git a/src/Composer/Repository/PearRepository.php b/src/Composer/Repository/PearRepository.php
index 1f882eb80..e2519d9b9 100644
--- a/src/Composer/Repository/PearRepository.php
+++ b/src/Composer/Repository/PearRepository.php
@@ -13,13 +13,13 @@
namespace Composer\Repository;
use Composer\IO\IOInterface;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Repository\Pear\ChannelReader;
use Composer\Package\CompletePackage;
use Composer\Repository\Pear\ChannelInfo;
use Composer\EventDispatcher\EventDispatcher;
use Composer\Package\Link;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
use Composer\Util\RemoteFilesystem;
use Composer\Config;
@@ -120,7 +120,7 @@ class PearRepository extends ArrayRepository
// cause we've know only repository channel alias
if ($channelInfo->getName() == $packageDefinition->getChannelName()) {
$composerPackageAlias = $this->buildComposerPackageName($channelInfo->getAlias(), $packageDefinition->getPackageName());
- $aliasConstraint = new VersionConstraint('==', $normalizedVersion);
+ $aliasConstraint = new Constraint('==', $normalizedVersion);
$replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
}
@@ -129,7 +129,7 @@ class PearRepository extends ArrayRepository
&& ($this->vendorAlias != 'pear-'.$channelInfo->getAlias() || $channelInfo->getName() != $packageDefinition->getChannelName())
) {
$composerPackageAlias = "{$this->vendorAlias}/{$packageDefinition->getPackageName()}";
- $aliasConstraint = new VersionConstraint('==', $normalizedVersion);
+ $aliasConstraint = new Constraint('==', $normalizedVersion);
$replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
}
diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php
index d7be746a2..44a70b83b 100644
--- a/src/Composer/Repository/PlatformRepository.php
+++ b/src/Composer/Repository/PlatformRepository.php
@@ -15,7 +15,7 @@ namespace Composer\Repository;
use Composer\Config;
use Composer\Package\PackageInterface;
use Composer\Package\CompletePackage;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Plugin\PluginInterface;
/**
diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php
index aaba31a9e..94e52af5f 100644
--- a/src/Composer/Repository/RepositoryInterface.php
+++ b/src/Composer/Repository/RepositoryInterface.php
@@ -38,8 +38,8 @@ interface RepositoryInterface extends \Countable
/**
* Searches for the first match of a package by name and version.
*
- * @param string $name package name
- * @param string|\Composer\Package\LinkConstraint\LinkConstraintInterface $constraint package version or version constraint to match against
+ * @param string $name package name
+ * @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
*
* @return PackageInterface|null
*/
@@ -48,17 +48,17 @@ interface RepositoryInterface extends \Countable
/**
* Searches for all packages matching a name and optionally a version.
*
- * @param string $name package name
- * @param string|\Composer\Package\LinkConstraint\LinkConstraintInterface $constraint package version or version constraint to match against
+ * @param string $name package name
+ * @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
*
- * @return array
+ * @return PackageInterface[]
*/
public function findPackages($name, $constraint = null);
/**
* Returns list of registered packages.
*
- * @return array
+ * @return PackageInterface[]
*/
public function getPackages();
diff --git a/src/Composer/Repository/RepositoryManager.php b/src/Composer/Repository/RepositoryManager.php
index 47c152398..372dc8979 100644
--- a/src/Composer/Repository/RepositoryManager.php
+++ b/src/Composer/Repository/RepositoryManager.php
@@ -15,6 +15,7 @@ namespace Composer\Repository;
use Composer\IO\IOInterface;
use Composer\Config;
use Composer\EventDispatcher\EventDispatcher;
+use Composer\Package\PackageInterface;
/**
* Repositories manager.
@@ -42,8 +43,8 @@ class RepositoryManager
/**
* Searches for a package by it's name and version in managed repositories.
*
- * @param string $name package name
- * @param string|\Composer\Package\LinkConstraint\LinkConstraintInterface $constraint package version or version constraint to match against
+ * @param string $name package name
+ * @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
*
* @return PackageInterface|null
*/
@@ -59,8 +60,8 @@ class RepositoryManager
/**
* Searches for all packages matching a name and optionally a version in managed repositories.
*
- * @param string $name package name
- * @param string|\Composer\Package\LinkConstraint\LinkConstraintInterface $constraint package version or version constraint to match against
+ * @param string $name package name
+ * @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
*
* @return array
*/
@@ -90,8 +91,8 @@ class RepositoryManager
*
* @param string $type repository type
* @param array $config repository configuration
- * @return RepositoryInterface
* @throws \InvalidArgumentException if repository for provided type is not registered
+ * @return RepositoryInterface
*/
public function createRepository($type, $config)
{
diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php
index fd2e71545..517012751 100644
--- a/src/Composer/Repository/Vcs/GitHubDriver.php
+++ b/src/Composer/Repository/Vcs/GitHubDriver.php
@@ -50,6 +50,9 @@ class GitHubDriver extends VcsDriver
$this->owner = $match[3];
$this->repository = $match[4];
$this->originUrl = !empty($match[1]) ? $match[1] : $match[2];
+ if ($this->originUrl === 'www.github.com') {
+ $this->originUrl = 'github.com';
+ }
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
if (isset($this->repoConfig['no-api']) && $this->repoConfig['no-api']) {
@@ -260,7 +263,7 @@ class GitHubDriver extends VcsDriver
}
$originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
- if (!in_array($originUrl, $config->get('github-domains'))) {
+ if (!in_array(preg_replace('{^www\.}i', '', $originUrl), $config->get('github-domains'))) {
return false;
}
diff --git a/src/Composer/Repository/Vcs/PerforceDriver.php b/src/Composer/Repository/Vcs/PerforceDriver.php
index c7c225b27..01d4a52d8 100644
--- a/src/Composer/Repository/Vcs/PerforceDriver.php
+++ b/src/Composer/Repository/Vcs/PerforceDriver.php
@@ -119,7 +119,7 @@ class PerforceDriver extends VcsDriver
'type' => 'perforce',
'url' => $this->repoConfig['url'],
'reference' => $identifier,
- 'p4user' => $this->perforce->getUser()
+ 'p4user' => $this->perforce->getUser(),
);
return $source;
diff --git a/src/Composer/Repository/Vcs/VcsDriverInterface.php b/src/Composer/Repository/Vcs/VcsDriverInterface.php
index dd30baacd..307d63ef6 100644
--- a/src/Composer/Repository/Vcs/VcsDriverInterface.php
+++ b/src/Composer/Repository/Vcs/VcsDriverInterface.php
@@ -77,14 +77,13 @@ interface VcsDriverInterface
* Return true if the repository has a composer file for a given identifier,
* false otherwise.
*
- * @param string $identifier Any identifier to a specific branch/tag/commit
- * @return boolean Whether the repository has a composer file for a given identifier.
+ * @param string $identifier Any identifier to a specific branch/tag/commit
+ * @return bool Whether the repository has a composer file for a given identifier.
*/
public function hasComposerFile($identifier);
/**
* Performs any cleanup necessary as the driver is not longer needed
- *
*/
public function cleanup();
diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php
index 034260d0c..b6ebd3b35 100644
--- a/src/Composer/Repository/VcsRepository.php
+++ b/src/Composer/Repository/VcsRepository.php
@@ -14,7 +14,7 @@ namespace Composer\Repository;
use Composer\Downloader\TransportException;
use Composer\Repository\Vcs\VcsDriverInterface;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Package\Loader\InvalidPackageException;
@@ -55,7 +55,7 @@ class VcsRepository extends ArrayRepository
$this->url = $repoConfig['url'];
$this->io = $io;
$this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
- $this->verbose = $io->isVerbose();
+ $this->verbose = $io->isVeryVerbose();
$this->config = $config;
$this->repoConfig = $repoConfig;
}
diff --git a/src/Composer/Repository/WritableArrayRepository.php b/src/Composer/Repository/WritableArrayRepository.php
index 756f24137..041e40562 100644
--- a/src/Composer/Repository/WritableArrayRepository.php
+++ b/src/Composer/Repository/WritableArrayRepository.php
@@ -42,7 +42,7 @@ class WritableArrayRepository extends ArrayRepository implements WritableReposit
{
$packages = $this->getPackages();
- // get at most one package of each name, prefering non-aliased ones
+ // get at most one package of each name, preferring non-aliased ones
$packagesByName = array();
foreach ($packages as $package) {
if (!isset($packagesByName[$package->getName()]) || $packagesByName[$package->getName()] instanceof AliasPackage) {
diff --git a/src/Composer/Repository/WritableRepositoryInterface.php b/src/Composer/Repository/WritableRepositoryInterface.php
index c046c377c..4500005d9 100644
--- a/src/Composer/Repository/WritableRepositoryInterface.php
+++ b/src/Composer/Repository/WritableRepositoryInterface.php
@@ -41,14 +41,14 @@ interface WritableRepositoryInterface extends RepositoryInterface
public function removePackage(PackageInterface $package);
/**
- * Get unique packages, with aliases resolved and removed
+ * Get unique packages (at most one package of each name), with aliases resolved and removed.
*
* @return PackageInterface[]
*/
public function getCanonicalPackages();
/**
- * Forces a reload of all packages
+ * Forces a reload of all packages.
*/
public function reload();
}
diff --git a/src/Composer/Script/Event.php b/src/Composer/Script/Event.php
index bde7e3b6f..138f43c1a 100644
--- a/src/Composer/Script/Event.php
+++ b/src/Composer/Script/Event.php
@@ -35,7 +35,7 @@ class Event extends BaseEvent
private $io;
/**
- * @var boolean Dev mode flag
+ * @var bool Dev mode flag
*/
private $devMode;
@@ -45,7 +45,7 @@ class Event extends BaseEvent
* @param string $name The event name
* @param Composer $composer The composer object
* @param IOInterface $io The IOInterface object
- * @param boolean $devMode Whether or not we are in dev mode
+ * @param bool $devMode Whether or not we are in dev mode
* @param array $args Arguments passed by the user
* @param array $flags Optional flags to pass data not as argument
*/
@@ -80,7 +80,7 @@ class Event extends BaseEvent
/**
* Return the dev mode flag
*
- * @return boolean
+ * @return bool
*/
public function isDevMode()
{
diff --git a/src/Composer/Util/ConfigValidator.php b/src/Composer/Util/ConfigValidator.php
index eac5619e7..a7ddaca9b 100644
--- a/src/Composer/Util/ConfigValidator.php
+++ b/src/Composer/Util/ConfigValidator.php
@@ -18,6 +18,7 @@ use Composer\Package\Loader\InvalidPackageException;
use Composer\Json\JsonValidationException;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
+use Composer\Spdx\SpdxLicenses;
/**
* Validates a composer configuration.
@@ -37,8 +38,8 @@ class ConfigValidator
/**
* Validates the config, and returns the result.
*
- * @param string $file The path to the file
- * @param integer $arrayLoaderValidationFlags Flags for ArrayLoader validation
+ * @param string $file The path to the file
+ * @param int $arrayLoaderValidationFlags Flags for ArrayLoader validation
*
* @return array a triple containing the errors, publishable errors, and warnings
*/
@@ -82,7 +83,7 @@ class ConfigValidator
}
}
- $licenseValidator = new SpdxLicense();
+ $licenseValidator = new SpdxLicenses();
if ('proprietary' !== $manifest['license'] && array() !== $manifest['license'] && !$licenseValidator->validate($manifest['license'])) {
$warnings[] = sprintf(
'License %s is not a valid SPDX license identifier, see http://www.spdx.org/licenses/ if you use an open license.'
@@ -123,6 +124,14 @@ class ConfigValidator
}
}
+ // check for empty psr-0/psr-4 namespace prefixes
+ if (isset($manifest['autoload']['psr-0'][''])) {
+ $warnings[] = "Defining autoload.psr-0 with an empty namespace prefix is a bad idea for performance";
+ }
+ if (isset($manifest['autoload']['psr-4'][''])) {
+ $warnings[] = "Defining autoload.psr-4 with an empty namespace prefix is a bad idea for performance";
+ }
+
try {
$loader = new ValidatingArrayLoader(new ArrayLoader(), true, null, $arrayLoaderValidationFlags);
if (!isset($manifest['version'])) {
diff --git a/src/Composer/Util/ErrorHandler.php b/src/Composer/Util/ErrorHandler.php
index b10cb15d5..399491f8c 100644
--- a/src/Composer/Util/ErrorHandler.php
+++ b/src/Composer/Util/ErrorHandler.php
@@ -58,6 +58,7 @@ class ErrorHandler
if (isset($a['line'], $a['file'])) {
return ' '.$a['file'].':'.$a['line'].'';
}
+
return null;
}, array_slice(debug_backtrace(), 2))));
}
diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php
index 92e5e0623..93b1a4010 100644
--- a/src/Composer/Util/Filesystem.php
+++ b/src/Composer/Util/Filesystem.php
@@ -88,10 +88,9 @@ class Filesystem
* Uses the process component if proc_open is enabled on the PHP
* installation.
*
- * @param string $directory
- * @return bool
- *
+ * @param string $directory
* @throws \RuntimeException
+ * @return bool
*/
public function removeDirectory($directory)
{
@@ -174,10 +173,9 @@ class Filesystem
/**
* Attempts to unlink a file and in case of failure retries after 350ms on windows
*
- * @param string $path
- * @return bool
- *
+ * @param string $path
* @throws \RuntimeException
+ * @return bool
*/
public function unlink($path)
{
@@ -200,10 +198,9 @@ class Filesystem
/**
* Attempts to rmdir a file and in case of failure retries after 350ms on windows
*
- * @param string $path
- * @return bool
- *
+ * @param string $path
* @throws \RuntimeException
+ * @return bool
*/
public function rmdir($path)
{
@@ -508,7 +505,14 @@ class Filesystem
return unlink($path);
}
- private function isSymlinkedDirectory($directory)
+ /**
+ * return true if that directory is a symlink.
+ *
+ * @param string $directory
+ *
+ * @return bool
+ */
+ public function isSymlinkedDirectory($directory)
{
if (!is_dir($directory)) {
return false;
diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php
index 5d84ebbf3..1d4a98294 100644
--- a/src/Composer/Util/Git.php
+++ b/src/Composer/Util/Git.php
@@ -105,9 +105,7 @@ class Git
return;
}
}
- } elseif ( // private non-github repo that failed to authenticate
- $this->isAuthenticationFailure($url, $match)
- ) {
+ } elseif ($this->isAuthenticationFailure($url, $match)) { // private non-github repo that failed to authenticate
if (strpos($match[2], '@')) {
list($authParts, $match[2]) = explode('@', $match[2], 2);
}
@@ -119,7 +117,7 @@ class Git
$defaultUsername = null;
if (isset($authParts) && $authParts) {
if (false !== strpos($authParts, ':')) {
- list($defaultUsername,) = explode(':', $authParts, 2);
+ list($defaultUsername, ) = explode(':', $authParts, 2);
} else {
$defaultUsername = $authParts;
}
diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php
index 22c67c61b..8aaa7db65 100644
--- a/src/Composer/Util/GitHub.php
+++ b/src/Composer/Util/GitHub.php
@@ -15,7 +15,6 @@ namespace Composer\Util;
use Composer\IO\IOInterface;
use Composer\Config;
use Composer\Downloader\TransportException;
-use Composer\Json\JsonFile;
/**
* @author Jordi Boggiano
@@ -95,6 +94,7 @@ class GitHub
if (!$token) {
$this->io->writeError('No token given, aborting.');
$this->io->writeError('You can also add it manually later by using "composer config github-oauth.github.com "');
+
return false;
}
diff --git a/src/Composer/Util/NoProxyPattern.php b/src/Composer/Util/NoProxyPattern.php
index 4e5c0c76b..994149268 100644
--- a/src/Composer/Util/NoProxyPattern.php
+++ b/src/Composer/Util/NoProxyPattern.php
@@ -114,7 +114,7 @@ class NoProxyPattern
* @param string $cidr IPv4 block in CIDR notation
* @param string $ip IPv4 address
*
- * @return boolean
+ * @return bool
*/
private static function inCIDRBlock($cidr, $ip)
{
diff --git a/src/Composer/Util/Perforce.php b/src/Composer/Util/Perforce.php
index 8e79f87b3..c1eaeebe9 100644
--- a/src/Composer/Util/Perforce.php
+++ b/src/Composer/Util/Perforce.php
@@ -297,7 +297,7 @@ class Perforce
}
throw new \Exception('p4 command not found in path: ' . $errorOutput);
}
- throw new \Exception('Invalid user name: ' . $this->getUser() );
+ throw new \Exception('Invalid user name: ' . $this->getUser());
}
return true;
@@ -305,7 +305,7 @@ class Perforce
public function connectClient()
{
- $p4CreateClientCommand = $this->generateP4Command('client -i < ' . str_replace( " ", "\\ ", $this->getP4ClientSpec() ));
+ $p4CreateClientCommand = $this->generateP4Command('client -i < ' . str_replace(" ", "\\ ", $this->getP4ClientSpec()));
$this->executeCommand($p4CreateClientCommand);
}
diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php
index 65367dad1..f3ad94a82 100644
--- a/src/Composer/Util/RemoteFilesystem.php
+++ b/src/Composer/Util/RemoteFilesystem.php
@@ -37,6 +37,7 @@ class RemoteFilesystem
private $retryAuthFailure;
private $lastHeaders;
private $storeAuth;
+ private $degradedMode = false;
/**
* Constructor.
@@ -55,11 +56,11 @@ class RemoteFilesystem
/**
* Copy the remote file in local.
*
- * @param string $originUrl The origin URL
- * @param string $fileUrl The file URL
- * @param string $fileName the local filename
- * @param boolean $progress Display the progression
- * @param array $options Additional context options
+ * @param string $originUrl The origin URL
+ * @param string $fileUrl The file URL
+ * @param string $fileName the local filename
+ * @param bool $progress Display the progression
+ * @param array $options Additional context options
*
* @return bool true
*/
@@ -71,10 +72,10 @@ class RemoteFilesystem
/**
* Get the content.
*
- * @param string $originUrl The origin URL
- * @param string $fileUrl The file URL
- * @param boolean $progress Display the progression
- * @param array $options Additional context options
+ * @param string $originUrl The origin URL
+ * @param string $fileUrl The file URL
+ * @param bool $progress Display the progression
+ * @param array $options Additional context options
*
* @return bool|string The content
*/
@@ -106,11 +107,11 @@ class RemoteFilesystem
/**
* Get file content or copy action.
*
- * @param string $originUrl The origin URL
- * @param string $fileUrl The file URL
- * @param array $additionalOptions context options
- * @param string $fileName the local filename
- * @param boolean $progress Display the progression
+ * @param string $originUrl The origin URL
+ * @param string $fileUrl The file URL
+ * @param array $additionalOptions context options
+ * @param string $fileName the local filename
+ * @param bool $progress Display the progression
*
* @throws TransportException|\Exception
* @throws TransportException When the file could not be downloaded
@@ -155,6 +156,10 @@ class RemoteFilesystem
if (isset($options['http'])) {
$options['http']['ignore_errors'] = true;
}
+ if ($this->degradedMode && substr($fileUrl, 0, 21) === 'http://packagist.org/') {
+ // access packagist using the resolved IPv4 instead of the hostname to force IPv4 protocol
+ $fileUrl = 'http://' . gethostbyname('packagist.org') . substr($fileUrl, 20);
+ }
$ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet')));
if ($this->progress) {
@@ -186,6 +191,16 @@ class RemoteFilesystem
}
restore_error_handler();
if (isset($e) && !$this->retry) {
+ if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
+ $this->degradedMode = true;
+ $this->io->writeError(array(
+ ''.$e->getMessage().'',
+ 'Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info',
+ ));
+
+ return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
+ }
+
throw $e;
}
@@ -201,36 +216,51 @@ class RemoteFilesystem
$result = false;
}
+ if ($this->progress && !$this->retry) {
+ $this->io->overwriteError(" Downloading: 100%");
+ }
+
// decode gzip
if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') {
$decode = false;
foreach ($http_response_header as $header) {
if (preg_match('{^content-encoding: *gzip *$}i', $header)) {
$decode = true;
- continue;
} elseif (preg_match('{^HTTP/}i', $header)) {
+ // In case of redirects, http_response_headers contains the headers of all responses
+ // so we reset the flag when a new response is being parsed as we are only interested in the last response
$decode = false;
}
}
if ($decode) {
- if (PHP_VERSION_ID >= 50400) {
- $result = zlib_decode($result);
- } else {
- // work around issue with gzuncompress & co that do not work with all gzip checksums
- $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
- }
+ try {
+ if (PHP_VERSION_ID >= 50400) {
+ $result = zlib_decode($result);
+ } else {
+ // work around issue with gzuncompress & co that do not work with all gzip checksums
+ $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
+ }
- if (!$result) {
- throw new TransportException('Failed to decode zlib stream');
+ if (!$result) {
+ throw new TransportException('Failed to decode zlib stream');
+ }
+ } catch (\Exception $e) {
+ if ($this->degradedMode) {
+ throw $e;
+ }
+
+ $this->degradedMode = true;
+ $this->io->writeError(array(
+ 'Failed to decode response: '.$e->getMessage().'',
+ 'Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info',
+ ));
+
+ return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
}
}
}
- if ($this->progress && !$this->retry) {
- $this->io->overwriteError(" Downloading: 100%");
- }
-
// handle copy command if download was successful
if (false !== $result && null !== $fileName) {
if ('' === $result) {
@@ -269,6 +299,16 @@ class RemoteFilesystem
$e->setHeaders($http_response_header);
}
+ if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
+ $this->degradedMode = true;
+ $this->io->writeError(array(
+ ''.$e->getMessage().'',
+ 'Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info',
+ ));
+
+ return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
+ }
+
throw $e;
}
@@ -282,12 +322,12 @@ class RemoteFilesystem
/**
* Get notification action.
*
- * @param integer $notificationCode The notification code
- * @param integer $severity The severity level
+ * @param int $notificationCode The notification code
+ * @param int $severity The severity level
* @param string $message The message
- * @param integer $messageCode The message code
- * @param integer $bytesTransferred The loaded size
- * @param integer $bytesMax The total size
+ * @param int $messageCode The message code
+ * @param int $bytesTransferred The loaded size
+ * @param int $bytesMax The total size
* @throws TransportException
*/
protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
@@ -302,7 +342,6 @@ class RemoteFilesystem
}
$this->promptAuthAndRetry($messageCode);
- break;
}
break;
@@ -314,7 +353,6 @@ class RemoteFilesystem
}
$this->promptAuthAndRetry($messageCode, $message);
- break;
}
break;
@@ -326,11 +364,7 @@ class RemoteFilesystem
case STREAM_NOTIFY_PROGRESS:
if ($this->bytesMax > 0 && $this->progress) {
- $progression = 0;
-
- if ($this->bytesMax > 0) {
- $progression = round($bytesTransferred / $this->bytesMax * 100);
- }
+ $progression = round($bytesTransferred / $this->bytesMax * 100);
if ((0 === $progression % 5) && 100 !== $progression && $progression !== $this->lastProgress) {
$this->lastProgress = $progression;
@@ -402,7 +436,7 @@ class RemoteFilesystem
php_uname('s'),
php_uname('r'),
$phpVersion
- )
+ ),
);
if (extension_loaded('zlib')) {
@@ -410,8 +444,12 @@ class RemoteFilesystem
}
$options = array_replace_recursive($this->options, $additionalOptions);
- $options['http']['protocol_version'] = 1.1;
- $headers[] = 'Connection: close';
+ if (!$this->degradedMode) {
+ // degraded mode disables HTTP/1.1 which causes issues with some bad
+ // proxies/software due to the use of chunked encoding
+ $options['http']['protocol_version'] = 1.1;
+ $headers[] = 'Connection: close';
+ }
if ($this->io->hasAuthentication($originUrl)) {
$auth = $this->io->getAuthentication($originUrl);
diff --git a/src/Composer/Util/SpdxLicense.php b/src/Composer/Util/SpdxLicense.php
index 650b918e4..8934de679 100644
--- a/src/Composer/Util/SpdxLicense.php
+++ b/src/Composer/Util/SpdxLicense.php
@@ -12,222 +12,13 @@
namespace Composer\Util;
-use Composer\Json\JsonFile;
+use Composer\Spdx\SpdxLicenses;
+
+@trigger_error('The ' . __NAMESPACE__ . '\SpdxLicense class is deprecated, use Composer\Spdx\SpdxLicenses instead.', E_USER_DEPRECATED);
/**
- * Supports composer array and SPDX tag notation for disjunctive/conjunctive
- * licenses.
- *
- * @author Tom Klingenberg
+ * @deprecated use Composer\Spdx\SpdxLicenses instead
*/
-class SpdxLicense
+class SpdxLicense extends SpdxLicenses
{
- /**
- * @var array
- */
- private $licenses;
-
- public function __construct()
- {
- $this->loadLicenses();
- }
-
- private function loadLicenses()
- {
- if (is_array($this->licenses)) {
- return $this->licenses;
- }
-
- $jsonFile = new JsonFile(__DIR__ . '/../../../res/spdx-licenses.json');
- $this->licenses = $jsonFile->read();
-
- return $this->licenses;
- }
-
- /**
- * Returns license metadata by license identifier.
- *
- * @param string $identifier
- *
- * @return array|null
- */
- public function getLicenseByIdentifier($identifier)
- {
- if (!isset($this->licenses[$identifier])) {
- return;
- }
-
- $license = $this->licenses[$identifier];
-
- // add URL for the license text (it's not included in the json)
- $license[2] = 'http://spdx.org/licenses/' . $identifier . '#licenseText';
-
- return $license;
- }
-
- /**
- * Returns the short identifier of a license by full name.
- *
- * @param string $identifier
- *
- * @return string
- */
- public function getIdentifierByName($name)
- {
- foreach ($this->licenses as $identifier => $licenseData) {
- if ($licenseData[0] === $name) { // key 0 = fullname
- return $identifier;
- }
- }
- }
-
- /**
- * Returns the OSI Approved status for a license by identifier.
- *
- * @return bool
- */
- public function isOsiApprovedByIdentifier($identifier)
- {
- return $this->licenses[$identifier][1]; // key 1 = osi approved
- }
-
- /**
- * Check, if the identifier for a license is valid.
- *
- * @param string $identifier
- *
- * @return bool
- */
- private function isValidLicenseIdentifier($identifier)
- {
- $identifiers = array_keys($this->licenses);
-
- return in_array($identifier, $identifiers);
- }
-
- /**
- * @param array|string $license
- *
- * @return bool
- * @throws \InvalidArgumentException
- */
- public function validate($license)
- {
- if (is_array($license)) {
- $count = count($license);
- if ($count !== count(array_filter($license, 'is_string'))) {
- throw new \InvalidArgumentException('Array of strings expected.');
- }
- $license = $count > 1 ? '('.implode(' or ', $license).')' : (string) reset($license);
- }
-
- if (!is_string($license)) {
- throw new \InvalidArgumentException(sprintf(
- 'Array or String expected, %s given.', gettype($license)
- ));
- }
-
- return $this->isValidLicenseString($license);
- }
-
- /**
- * @param string $license
- *
- * @return bool
- * @throws \RuntimeException
- */
- private function isValidLicenseString($license)
- {
- $tokens = array(
- 'po' => '\(',
- 'pc' => '\)',
- 'op' => '(?:or|and)',
- 'lix' => '(?:NONE|NOASSERTION)',
- 'lir' => 'LicenseRef-\d+',
- 'lic' => '[-+_.a-zA-Z0-9]{3,}',
- 'ws' => '\s+',
- '_' => '.',
- );
-
- $next = function () use ($license, $tokens) {
- static $offset = 0;
-
- if ($offset >= strlen($license)) {
- return null;
- }
-
- foreach ($tokens as $name => $token) {
- if (false === $r = preg_match('{' . $token . '}', $license, $matches, PREG_OFFSET_CAPTURE, $offset)) {
- throw new \RuntimeException('Pattern for token %s failed (regex error).', $name);
- }
- if ($r === 0) {
- continue;
- }
- if ($matches[0][1] !== $offset) {
- continue;
- }
- $offset += strlen($matches[0][0]);
-
- return array($name, $matches[0][0]);
- }
-
- throw new \RuntimeException('At least the last pattern needs to match, but it did not (dot-match-all is missing?).');
- };
-
- $open = 0;
- $require = 1;
- $lastop = null;
-
- while (list($token, $string) = $next()) {
- switch ($token) {
- case 'po':
- if ($open || !$require) {
- return false;
- }
- $open = 1;
- break;
- case 'pc':
- if ($open !== 1 || $require || !$lastop) {
- return false;
- }
- $open = 2;
- break;
- case 'op':
- if ($require || !$open) {
- return false;
- }
- $lastop || $lastop = $string;
- if ($lastop !== $string) {
- return false;
- }
- $require = 1;
- break;
- case 'lix':
- if ($open) {
- return false;
- }
- goto lir;
- case 'lic':
- if (!$this->isValidLicenseIdentifier($string)) {
- return false;
- }
- // Fall-through intended
- case 'lir':
- lir:
- if (!$require) {
- return false;
- }
- $require = 0;
- break;
- case 'ws':
- break;
- case '_':
- return false;
- default:
- throw new \RuntimeException(sprintf('Unparsed token: %s.', print_r($token, true)));
- }
- }
-
- return !($open % 2 || $require);
- }
}
diff --git a/src/Composer/Util/SpdxLicensesUpdater.php b/src/Composer/Util/SpdxLicensesUpdater.php
deleted file mode 100644
index efcc30065..000000000
--- a/src/Composer/Util/SpdxLicensesUpdater.php
+++ /dev/null
@@ -1,67 +0,0 @@
-
- * Jordi Boggiano
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Util;
-
-use Composer\Json\JsonFormatter;
-
-/**
- * The SPDX Licenses Updater scrapes licenses from the spdx website
- * and updates the "res/spdx-licenses.json" file accordingly.
- *
- * The class is used by the update script "bin/update-spdx-licenses".
- */
-class SpdxLicensesUpdater
-{
- private $licensesUrl = 'http://www.spdx.org/licenses/';
-
- public function update()
- {
- $json = json_encode($this->getLicenses(), true);
- $prettyJson = JsonFormatter::format($json, true, true);
- file_put_contents(__DIR__ . '/../../../res/spdx-licenses.json', $prettyJson);
- }
-
- private function getLicenses()
- {
- $licenses = array();
-
- $dom = new \DOMDocument;
- $dom->loadHTMLFile($this->licensesUrl);
-
- $xPath = new \DOMXPath($dom);
- $trs = $xPath->query('//table//tbody//tr');
-
- // iterate over each row in the table
- foreach ($trs as $tr) {
- $tds = $tr->getElementsByTagName('td'); // get the columns in this row
-
- if ($tds->length < 4) {
- throw new \Exception('Obtaining the license table failed. Wrong table format. Found less than 4 cells in a row.');
- }
-
- if (trim($tds->item(3)->nodeValue) == 'License Text') {
- $fullname = trim($tds->item(0)->nodeValue);
- $identifier = trim($tds->item(1)->nodeValue);
- $osiApproved = ((isset($tds->item(2)->nodeValue) && $tds->item(2)->nodeValue === 'Y')) ? true : false;
-
- // The license URL is not scraped intentionally to keep json file size low.
- // It's build when requested, see SpdxLicense->getLicenseByIdentifier().
- //$licenseURL = = $tds->item(3)->getAttribute('href');
-
- $licenses += array($identifier => array($fullname, $osiApproved));
- }
- }
-
- return $licenses;
- }
-}
diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php
index ffeaf3f83..cd8c05d92 100644
--- a/src/Composer/Util/StreamContextFactory.php
+++ b/src/Composer/Util/StreamContextFactory.php
@@ -26,8 +26,8 @@ final class StreamContextFactory
* @param string $url URL the context is to be used for
* @param array $defaultOptions Options to merge with the default
* @param array $defaultParams Parameters to specify on the context
- * @return resource Default context
* @throws \RuntimeException if https proxy required and OpenSSL uninstalled
+ * @return resource Default context
*/
public static function getContext($url, array $defaultOptions = array(), array $defaultParams = array())
{
diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php
index d5694b3be..4117499c8 100644
--- a/src/Composer/Util/Svn.php
+++ b/src/Composer/Util/Svn.php
@@ -54,7 +54,7 @@ class Svn
protected $process;
/**
- * @var integer
+ * @var int
*/
protected $qtyAuthTries = 0;
@@ -94,9 +94,8 @@ class Svn
* @param string $path Target for a checkout
* @param bool $verbose Output all output to the user
*
- * @return string
- *
* @throws \RuntimeException
+ * @return string
*/
public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
{
@@ -147,7 +146,7 @@ class Svn
}
/**
- * @param boolean $cacheCredentials
+ * @param bool $cacheCredentials
*/
public function setCacheCredentials($cacheCredentials)
{
@@ -157,8 +156,8 @@ class Svn
/**
* Repositories requests credentials, let's put them in.
*
- * @return \Composer\Util\Svn
* @throws \RuntimeException
+ * @return \Composer\Util\Svn
*/
protected function doAuthDance()
{
@@ -229,8 +228,8 @@ class Svn
/**
* Get the password for the svn command. Can be empty.
*
- * @return string
* @throws \LogicException
+ * @return string
*/
protected function getPassword()
{
@@ -244,8 +243,8 @@ class Svn
/**
* Get the username for the svn command.
*
- * @return string
* @throws \LogicException
+ * @return string
*/
protected function getUsername()
{
diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php
index dbb7d2fad..8c7727058 100644
--- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php
+++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php
@@ -200,7 +200,7 @@ class AutoloadGeneratorTest extends TestCase
$package->setDevAutoload(array(
'files' => array('devfiles/foo.php'),
'psr-0' => array(
- 'Main' => 'tests/'
+ 'Main' => 'tests/',
),
));
@@ -381,7 +381,7 @@ class AutoloadGeneratorTest extends TestCase
$package->setAutoload(array(
'psr-0' => array('Prefix' => 'foo/bar/non/existing/'),
- 'psr-4' => array('Prefix\\' => 'foo/bar/non/existing2/')
+ 'psr-4' => array('Prefix\\' => 'foo/bar/non/existing2/'),
));
$this->repository->expects($this->once())
@@ -512,35 +512,35 @@ class AutoloadGeneratorTest extends TestCase
$packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0');
$packages[] = $c = new Package('c/c', '1.0', '1.0');
- $a->setAutoload(array('classmap' => array('')));
- $b->setAutoload(array('classmap' => array('test.php')));
- $c->setAutoload(array('classmap' => array('./')));
+ $a->setAutoload(array('psr-4' => array('' => 'src/')));
+ $b->setAutoload(array('psr-4' => array('' => './')));
+ $c->setAutoload(array('psr-4' => array('' => 'foo/')));
$this->repository->expects($this->once())
->method('getCanonicalPackages')
->will($this->returnValue($packages));
- $this->configValueMap['classmap-authoritative'] = true;
-
$this->fs->ensureDirectoryExists($this->vendorDir.'/composer');
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src');
$this->fs->ensureDirectoryExists($this->vendorDir.'/b/b');
$this->fs->ensureDirectoryExists($this->vendorDir.'/c/c/foo');
- file_put_contents($this->vendorDir.'/a/a/src/a.php', 'vendorDir.'/b/b/test.php', 'vendorDir.'/c/c/foo/test.php', 'vendorDir.'/a/a/src/ClassMapFoo.php', 'vendorDir.'/b/b/ClassMapBar.php', 'vendorDir.'/c/c/foo/ClassMapBaz.php', 'generator->setClassMapAuthoritative(true);
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_7');
+
$this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->assertEquals(
array(
- 'ClassMapBar' => $this->vendorDir.'/b/b/test.php',
- 'ClassMapBaz' => $this->vendorDir.'/c/c/foo/test.php',
- 'ClassMapFoo' => $this->vendorDir.'/a/a/src/a.php',
+ 'ClassMapBar' => $this->vendorDir.'/b/b/ClassMapBar.php',
+ 'ClassMapBaz' => $this->vendorDir.'/c/c/foo/ClassMapBaz.php',
+ 'ClassMapFoo' => $this->vendorDir.'/a/a/src/ClassMapFoo.php',
),
include $this->vendorDir.'/composer/autoload_classmap.php'
);
- $this->assertAutoloadFiles('classmap5', $this->vendorDir.'/composer', 'classmap');
+ $this->assertAutoloadFiles('classmap8', $this->vendorDir.'/composer', 'classmap');
$this->assertContains('$loader->setClassMapAuthoritative(true);', file_get_contents($this->vendorDir.'/composer/autoload_real.php'));
}
@@ -585,6 +585,71 @@ class AutoloadGeneratorTest extends TestCase
$this->assertTrue(function_exists('testFilesAutoloadGenerationRoot'));
}
+ public function testFilesAutoloadGenerationRemoveExtraEntitiesFromAutoloadFiles()
+ {
+ $autoloadPackage = new Package('a', '1.0', '1.0');
+ $autoloadPackage->setAutoload(array('files' => array('root.php')));
+ $autoloadPackage->setIncludePaths(array('/lib', '/src'));
+
+ $notAutoloadPackage = new Package('a', '1.0', '1.0');
+
+ $autoloadPackages = array();
+ $autoloadPackages[] = $a = new Package('a/a', '1.0', '1.0');
+ $autoloadPackages[] = $b = new Package('b/b', '1.0', '1.0');
+ $autoloadPackages[] = $c = new Package('c/c', '1.0', '1.0');
+ $a->setAutoload(array('files' => array('test.php')));
+ $a->setIncludePaths(array('lib1', 'src1'));
+ $b->setAutoload(array('files' => array('test2.php')));
+ $b->setIncludePaths(array('lib2'));
+ $c->setAutoload(array('files' => array('test3.php', 'foo/bar/test4.php')));
+ $c->setIncludePaths(array('lib3'));
+ $c->setTargetDir('foo/bar');
+
+ $notAutoloadPackages = array();
+ $notAutoloadPackages[] = $a = new Package('a/a', '1.0', '1.0');
+ $notAutoloadPackages[] = $b = new Package('b/b', '1.0', '1.0');
+ $notAutoloadPackages[] = $c = new Package('c/c', '1.0', '1.0');
+
+ $this->repository->expects($this->at(0))
+ ->method('getCanonicalPackages')
+ ->will($this->returnValue($autoloadPackages));
+
+ $this->repository->expects($this->at(1))
+ ->method('getCanonicalPackages')
+ ->will($this->returnValue($notAutoloadPackages));
+
+ $this->repository->expects($this->at(2))
+ ->method('getCanonicalPackages')
+ ->will($this->returnValue($notAutoloadPackages));
+
+ $this->fs->ensureDirectoryExists($this->vendorDir.'/a/a');
+ $this->fs->ensureDirectoryExists($this->vendorDir.'/b/b');
+ $this->fs->ensureDirectoryExists($this->vendorDir.'/c/c/foo/bar');
+ file_put_contents($this->vendorDir.'/a/a/test.php', 'vendorDir.'/b/b/test2.php', 'vendorDir.'/c/c/foo/bar/test3.php', 'vendorDir.'/c/c/foo/bar/test4.php', 'workingDir.'/root.php', 'generator->dump($this->config, $this->repository, $autoloadPackage, $this->im, 'composer', false, 'FilesAutoload');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_functions.php', $this->vendorDir.'/autoload.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_real_functions_with_include_paths.php', $this->vendorDir.'/composer/autoload_real.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_files_functions.php', $this->vendorDir.'/composer/autoload_files.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/include_paths_functions.php', $this->vendorDir.'/composer/include_paths.php');
+
+ $this->generator->dump($this->config, $this->repository, $autoloadPackage, $this->im, 'composer', false, 'FilesAutoload');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_functions.php', $this->vendorDir.'/autoload.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_real_functions_with_include_paths.php', $this->vendorDir.'/composer/autoload_real.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_files_functions_with_removed_extra.php', $this->vendorDir.'/composer/autoload_files.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/include_paths_functions_with_removed_extra.php', $this->vendorDir.'/composer/include_paths.php');
+
+ $this->generator->dump($this->config, $this->repository, $notAutoloadPackage, $this->im, 'composer', false, 'FilesAutoload');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_functions.php', $this->vendorDir.'/autoload.php');
+ $this->assertFileEquals(__DIR__.'/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php', $this->vendorDir.'/composer/autoload_real.php');
+ $this->assertFileNotExists($this->vendorDir.'/composer/autoload_files.php');
+ $this->assertFileNotExists($this->vendorDir.'/composer/include_paths.php');
+ }
+
public function testFilesAutoloadOrderByDependencies()
{
$package = new Package('a', '1.0', '1.0');
@@ -655,7 +720,7 @@ class AutoloadGeneratorTest extends TestCase
$mainPackage = new Package('z', '1.0', '1.0');
$mainPackage->setAutoload(array(
'psr-0' => array('A\\B' => $this->workingDir.'/lib'),
- 'classmap' => array($this->workingDir.'/src')
+ 'classmap' => array($this->workingDir.'/src'),
));
$mainPackage->setRequires(array(new Link('z', 'a/a')));
diff --git a/tests/Composer/Test/Autoload/ClassLoaderTest.php b/tests/Composer/Test/Autoload/ClassLoaderTest.php
index ec4156a15..50772101e 100644
--- a/tests/Composer/Test/Autoload/ClassLoaderTest.php
+++ b/tests/Composer/Test/Autoload/ClassLoaderTest.php
@@ -9,17 +9,6 @@ use Composer\Autoload\ClassLoader;
*/
class ClassLoaderTest extends \PHPUnit_Framework_TestCase
{
- public function testLoadClassDotPhp()
- {
- $loader = new ClassLoader();
- $loader->add('DirDotPhp\\', __DIR__ . '/Fixtures');
- $loader->addPsr4('DirDotPhp\\', __DIR__ . '/Fixtures/DirDotPhp/psr4');
-
- $class = 'DirDotPhp\\Dir';
- $loader->loadClass($class);
- $this->assertTrue(class_exists($class, false), "->loadClass() loads '$class'.");
- }
-
/**
* Tests regular PSR-0 and PSR-4 class loading.
*
diff --git a/tests/Composer/Test/Autoload/Fixtures/DirDotPhp/Dir.php b/tests/Composer/Test/Autoload/Fixtures/DirDotPhp/Dir.php
deleted file mode 100644
index 9d9d62d8c..000000000
--- a/tests/Composer/Test/Autoload/Fixtures/DirDotPhp/Dir.php
+++ /dev/null
@@ -1,6 +0,0 @@
- $vendorDir . '/b/b/ClassMapBar.php',
+ 'ClassMapBaz' => $vendorDir . '/c/c/foo/ClassMapBaz.php',
+ 'ClassMapFoo' => $vendorDir . '/a/a/src/ClassMapFoo.php',
+);
diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_files_functions_with_removed_extra.php b/tests/Composer/Test/Autoload/Fixtures/autoload_files_functions_with_removed_extra.php
new file mode 100644
index 000000000..8d124df37
--- /dev/null
+++ b/tests/Composer/Test/Autoload/Fixtures/autoload_files_functions_with_removed_extra.php
@@ -0,0 +1,10 @@
+ $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+
+ $loader->register(true);
+
+ $includeFiles = require __DIR__ . '/autoload_files.php';
+ foreach ($includeFiles as $file) {
+ composerRequireFilesAutoload($file);
+ }
+
+ return $loader;
+ }
+}
+
+function composerRequireFilesAutoload($file)
+{
+ require $file;
+}
diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php
new file mode 100644
index 000000000..205cd7158
--- /dev/null
+++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php
@@ -0,0 +1,50 @@
+ $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
+
+function composerRequireFilesAutoload($file)
+{
+ require $file;
+}
diff --git a/tests/Composer/Test/Autoload/Fixtures/include_paths_functions.php b/tests/Composer/Test/Autoload/Fixtures/include_paths_functions.php
new file mode 100644
index 000000000..f1095cf67
--- /dev/null
+++ b/tests/Composer/Test/Autoload/Fixtures/include_paths_functions.php
@@ -0,0 +1,15 @@
+ array('type' => 'composer', 'url' => 'https?://packagist.org', 'allow_ssl_downgrade' => true)
+ 'packagist' => array('type' => 'composer', 'url' => 'https?://packagist.org', 'allow_ssl_downgrade' => true),
),
array(),
);
@@ -44,7 +44,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
array(),
array(
array('packagist' => false),
- )
+ ),
);
$data['local config adds above defaults'] = array(
@@ -62,7 +62,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$data['system config adds above core defaults'] = array(
array(
'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
- 'packagist' => array('type' => 'composer', 'url' => 'https?://packagist.org', 'allow_ssl_downgrade' => true)
+ 'packagist' => array('type' => 'composer', 'url' => 'https?://packagist.org', 'allow_ssl_downgrade' => true),
),
array(),
array(
@@ -73,11 +73,11 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$data['local config can disable repos by name and re-add them anonymously to bring them above system config'] = array(
array(
0 => array('type' => 'composer', 'url' => 'http://packagist.org'),
- 'example.com' => array('type' => 'composer', 'url' => 'http://example.com')
+ 'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
),
array(
array('packagist' => false),
- array('type' => 'composer', 'url' => 'http://packagist.org')
+ array('type' => 'composer', 'url' => 'http://packagist.org'),
),
array(
'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
@@ -87,10 +87,10 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$data['local config can override by name to bring a repo above system config'] = array(
array(
'packagist' => array('type' => 'composer', 'url' => 'http://packagistnew.org'),
- 'example.com' => array('type' => 'composer', 'url' => 'http://example.com')
+ 'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
),
array(
- 'packagist' => array('type' => 'composer', 'url' => 'http://packagistnew.org')
+ 'packagist' => array('type' => 'composer', 'url' => 'http://packagistnew.org'),
),
array(
'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
@@ -139,7 +139,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$config->merge(array('config' => array(
'bin-dir' => '$HOME/foo',
'cache-dir' => '/baz/',
- 'vendor-dir' => 'vendor'
+ 'vendor-dir' => 'vendor',
)));
$home = rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '\\/');
@@ -153,7 +153,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$config = new Config(false, '/foo/bar');
$config->merge(array('config' => array(
'bin-dir' => '{$vendor-dir}/foo',
- 'vendor-dir' => 'vendor'
+ 'vendor-dir' => 'vendor',
)));
$this->assertEquals('/foo/bar/vendor', $config->get('vendor-dir'));
diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
index 993cbffe8..d694813c6 100644
--- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
+++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
@@ -18,7 +18,7 @@ use Composer\DependencyResolver\DefaultPolicy;
use Composer\DependencyResolver\Pool;
use Composer\Package\Link;
use Composer\Package\AliasPackage;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
use Composer\TestCase;
class DefaultPolicyTest extends TestCase
@@ -158,7 +158,7 @@ class DefaultPolicyTest extends TestCase
$this->pool->addRepository($this->repoImportant);
$this->pool->addRepository($this->repo);
- $packages = $this->pool->whatProvides('a', new VersionConstraint('=', '2.1.9999999.9999999-dev'));
+ $packages = $this->pool->whatProvides('a', new Constraint('=', '2.1.9999999.9999999-dev'));
$literals = array();
foreach ($packages as $package) {
$literals[] = $package->getId();
@@ -176,8 +176,8 @@ class DefaultPolicyTest extends TestCase
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
$this->repo->addPackage($packageB = $this->getPackage('B', '2.0'));
- $packageA->setProvides(array(new Link('A', 'X', new VersionConstraint('==', '1.0'), 'provides')));
- $packageB->setProvides(array(new Link('B', 'X', new VersionConstraint('==', '1.0'), 'provides')));
+ $packageA->setProvides(array(new Link('A', 'X', new Constraint('==', '1.0'), 'provides')));
+ $packageB->setProvides(array(new Link('B', 'X', new Constraint('==', '1.0'), 'provides')));
$this->pool->addRepository($this->repo);
@@ -194,7 +194,7 @@ class DefaultPolicyTest extends TestCase
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
$this->repo->addPackage($packageB = $this->getPackage('B', '2.0'));
- $packageB->setReplaces(array(new Link('B', 'A', new VersionConstraint('==', '1.0'), 'replaces')));
+ $packageB->setReplaces(array(new Link('B', 'A', new Constraint('==', '1.0'), 'replaces')));
$this->pool->addRepository($this->repo);
@@ -212,8 +212,8 @@ class DefaultPolicyTest extends TestCase
$this->repo->addPackage($packageB = $this->getPackage('vendor-b/replacer', '1.0'));
$this->repo->addPackage($packageA = $this->getPackage('vendor-a/replacer', '1.0'));
- $packageA->setReplaces(array(new Link('vendor-a/replacer', 'vendor-a/package', new VersionConstraint('==', '1.0'), 'replaces')));
- $packageB->setReplaces(array(new Link('vendor-b/replacer', 'vendor-a/package', new VersionConstraint('==', '1.0'), 'replaces')));
+ $packageA->setReplaces(array(new Link('vendor-a/replacer', 'vendor-a/package', new Constraint('==', '1.0'), 'replaces')));
+ $packageB->setReplaces(array(new Link('vendor-b/replacer', 'vendor-a/package', new Constraint('==', '1.0'), 'replaces')));
$this->pool->addRepository($this->repo);
diff --git a/tests/Composer/Test/DependencyResolver/RuleTest.php b/tests/Composer/Test/DependencyResolver/RuleTest.php
index 6688b24aa..f71af15bd 100644
--- a/tests/Composer/Test/DependencyResolver/RuleTest.php
+++ b/tests/Composer/Test/DependencyResolver/RuleTest.php
@@ -13,6 +13,7 @@
namespace Composer\Test\DependencyResolver;
use Composer\DependencyResolver\Rule;
+use Composer\DependencyResolver\RuleSet;
use Composer\DependencyResolver\Pool;
use Composer\Repository\ArrayRepository;
use Composer\TestCase;
@@ -30,15 +31,8 @@ class RuleTest extends TestCase
{
$rule = new Rule(array(123), 'job1', null);
- $this->assertEquals(substr(md5('123'), 0, 5), $rule->getHash());
- }
-
- public function testSetAndGetId()
- {
- $rule = new Rule(array(), 'job1', null);
- $rule->setId(666);
-
- $this->assertEquals(666, $rule->getId());
+ $hash = unpack('ihash', md5('123', true));
+ $this->assertEquals($hash['hash'], $rule->getHash());
}
public function testEqualsForRulesWithDifferentHashes()
@@ -68,9 +62,9 @@ class RuleTest extends TestCase
public function testSetAndGetType()
{
$rule = new Rule(array(), 'job1', null);
- $rule->setType('someType');
+ $rule->setType(RuleSet::TYPE_JOB);
- $this->assertEquals('someType', $rule->getType());
+ $this->assertEquals(RuleSet::TYPE_JOB, $rule->getType());
}
public function testEnable()
diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php
index e50b38b93..2c67d7464 100644
--- a/tests/Composer/Test/DependencyResolver/SolverTest.php
+++ b/tests/Composer/Test/DependencyResolver/SolverTest.php
@@ -19,7 +19,7 @@ use Composer\DependencyResolver\Solver;
use Composer\DependencyResolver\SolverProblemsException;
use Composer\Package\Link;
use Composer\TestCase;
-use Composer\Package\LinkConstraint\MultiConstraint;
+use Composer\Semver\Constraint\MultiConstraint;
class SolverTest extends TestCase
{
@@ -503,7 +503,7 @@ class SolverTest extends TestCase
$this->repo->addPackage($packageX = $this->getPackage('X', '1.0'));
$packageX->setRequires(array(
'a' => new Link('X', 'A', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires'),
- 'b' => new Link('X', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires')
+ 'b' => new Link('X', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires'),
));
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0.0'));
@@ -522,7 +522,7 @@ class SolverTest extends TestCase
$this->repo->addPackage($packageS = $this->getPackage('S', '2.0.0'));
$packageS->setReplaces(array(
'a' => new Link('S', 'A', $this->getVersionConstraint('>=', '2.0.0.0'), 'replaces'),
- 'b' => new Link('S', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'replaces')
+ 'b' => new Link('S', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'replaces'),
));
$this->reposComplete();
@@ -850,13 +850,13 @@ class SolverTest extends TestCase
$result[] = array(
'job' => 'update',
'from' => $operation->getInitialPackage(),
- 'to' => $operation->getTargetPackage()
+ 'to' => $operation->getTargetPackage(),
);
} else {
$job = ('uninstall' === $operation->getJobType() ? 'remove' : 'install');
$result[] = array(
'job' => $job,
- 'package' => $operation->getPackage()
+ 'package' => $operation->getPackage(),
);
}
}
diff --git a/tests/Composer/Test/Downloader/PearPackageExtractorTest.php b/tests/Composer/Test/Downloader/PearPackageExtractorTest.php
index 5429d109d..10ac27955 100644
--- a/tests/Composer/Test/Downloader/PearPackageExtractorTest.php
+++ b/tests/Composer/Test/Downloader/PearPackageExtractorTest.php
@@ -46,7 +46,7 @@ class PearPackageExtractorTest extends \PHPUnit_Framework_TestCase
'to' => 'PEAR/Frontend/Gtk/xpm/black_close_icon.xpm',
'role' => 'php',
'tasks' => array(),
- )
+ ),
);
$this->assertSame($expectedFileActions, $fileActions);
}
@@ -69,7 +69,7 @@ class PearPackageExtractorTest extends \PHPUnit_Framework_TestCase
'to' => 'Net/URL.php',
'role' => 'php',
'tasks' => array(),
- )
+ ),
);
$this->assertSame($expectedFileActions, $fileActions);
}
@@ -99,16 +99,16 @@ class PearPackageExtractorTest extends \PHPUnit_Framework_TestCase
'role' => 'php',
'tasks' => array(),
),
- 'php/Test.php' => array (
+ 'php/Test.php' => array(
'from' => 'Zend_Authentication-2.0.0beta4/php/Test.php',
'to' => '/php/Test.php',
'role' => 'script',
- 'tasks' => array (
- array (
+ 'tasks' => array(
+ array(
'from' => '@version@',
'to' => 'version',
- )
- )
+ ),
+ ),
),
'renamedFile.php' => array(
'from' => 'Zend_Authentication-2.0.0beta4/renamedFile.php',
diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
index 06d9c652d..925772d42 100644
--- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
+++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
@@ -13,7 +13,6 @@
namespace Composer\Test\EventDispatcher;
use Composer\EventDispatcher\Event;
-use Composer\EventDispatcher\EventDispatcher;
use Composer\Installer\InstallerEvents;
use Composer\TestCase;
use Composer\Script\ScriptEvents;
@@ -29,10 +28,18 @@ class EventDispatcherTest extends TestCase
{
$io = $this->getMock('Composer\IO\IOInterface');
$dispatcher = $this->getDispatcherStubForListenersTest(array(
- 'Composer\Test\EventDispatcher\EventDispatcherTest::call'
+ 'Composer\Test\EventDispatcher\EventDispatcherTest::call',
), $io);
- $io->expects($this->once())
+ $io->expects($this->at(0))
+ ->method('isVerbose')
+ ->willReturn(0);
+
+ $io->expects($this->at(1))
+ ->method('writeError')
+ ->with('> Composer\Test\EventDispatcher\EventDispatcherTest::call');
+
+ $io->expects($this->at(2))
->method('writeError')
->with('Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception');
@@ -43,7 +50,7 @@ class EventDispatcherTest extends TestCase
{
$io = $this->getMock('Composer\IO\IOInterface');
$dispatcher = $this->getDispatcherStubForListenersTest(array(
- 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsCommandEvent'
+ 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsCommandEvent',
), $io);
$this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
@@ -53,7 +60,7 @@ class EventDispatcherTest extends TestCase
{
$io = $this->getMock('Composer\IO\IOInterface');
$dispatcher = $this->getDispatcherStubForListenersTest(array(
- 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsVariableEvent'
+ 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsVariableEvent',
), $io);
$this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
@@ -94,12 +101,11 @@ class EventDispatcherTest extends TestCase
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
->setConstructorArgs(array(
$this->getMock('Composer\Composer'),
- $this->getMock('Composer\IO\IOInterface'),
+ $io = $this->getMock('Composer\IO\IOInterface'),
$process,
))
->setMethods(array(
'getListeners',
- 'executeEventPhpScript',
))
->getMock();
@@ -112,14 +118,26 @@ class EventDispatcherTest extends TestCase
'Composer\\Test\\EventDispatcher\\EventDispatcherTest::someMethod',
'echo -n bar',
);
+
$dispatcher->expects($this->atLeastOnce())
->method('getListeners')
->will($this->returnValue($listeners));
- $dispatcher->expects($this->once())
- ->method('executeEventPhpScript')
- ->with('Composer\Test\EventDispatcher\EventDispatcherTest', 'someMethod')
- ->will($this->returnValue(true));
+ $io->expects($this->any())
+ ->method('isVerbose')
+ ->willReturn(1);
+
+ $io->expects($this->at(1))
+ ->method('writeError')
+ ->with($this->equalTo('> post-install-cmd: echo -n foo'));
+
+ $io->expects($this->at(3))
+ ->method('writeError')
+ ->with($this->equalTo('> post-install-cmd: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'));
+
+ $io->expects($this->at(5))
+ ->method('writeError')
+ ->with($this->equalTo('> post-install-cmd: echo -n bar'));
$dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
}
@@ -150,12 +168,12 @@ class EventDispatcherTest extends TestCase
);
}
- public function testDispatcherOutputsCommands()
+ public function testDispatcherOutputsCommand()
{
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
->setConstructorArgs(array(
$this->getMock('Composer\Composer'),
- $this->getMock('Composer\IO\IOInterface'),
+ $io = $this->getMock('Composer\IO\IOInterface'),
new ProcessExecutor,
))
->setMethods(array('getListeners'))
@@ -166,6 +184,10 @@ class EventDispatcherTest extends TestCase
->method('getListeners')
->will($this->returnValue($listener));
+ $io->expects($this->once())
+ ->method('writeError')
+ ->with($this->equalTo('> echo foo'));
+
ob_start();
$dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
$this->assertEquals('foo', trim(ob_get_clean()));
@@ -188,7 +210,15 @@ class EventDispatcherTest extends TestCase
->method('getListeners')
->will($this->returnValue($listener));
- $io->expects($this->once())
+ $io->expects($this->at(0))
+ ->method('isVerbose')
+ ->willReturn(0);
+
+ $io->expects($this->at(1))
+ ->method('writeError')
+ ->willReturn('> exit 1');
+
+ $io->expects($this->at(2))
->method('writeError')
->with($this->equalTo('Script '.$code.' handling the post-install-cmd event returned with an error'));
diff --git a/tests/Composer/Test/Fixtures/installer/update-picks-up-change-of-vcs-type.test b/tests/Composer/Test/Fixtures/installer/update-picks-up-change-of-vcs-type.test
new file mode 100644
index 000000000..1e528d047
--- /dev/null
+++ b/tests/Composer/Test/Fixtures/installer/update-picks-up-change-of-vcs-type.test
@@ -0,0 +1,57 @@
+--TEST--
+Converting from one VCS type to another (including an URL change) should update the lock file.
+--COMPOSER--
+{
+ "repositories": [
+ {
+ "type": "package",
+ "package": [
+ {
+ "name": "a/a", "version": "1.0.0",
+ "source": { "reference": "new-git-ref", "type": "git", "url": "new-git-url" }
+ }
+ ]
+ }
+ ],
+ "require": {
+ "a/a": "1.0.0"
+ }
+}
+--INSTALLED--
+[
+ {
+ "name": "a/a", "version": "1.0.0",
+ "source": { "reference": "old-hg-ref", "type": "hg", "url": "old-hg-url" }
+ }
+]
+--LOCK--
+{
+ "packages": [
+ {
+ "name": "a/a", "version": "1.0.0",
+ "source": { "reference": "old-hg-ref", "type": "hg", "url": "old-hg-url" }
+ }
+ ]
+}
+--RUN--
+update
+--EXPECT-LOCK--
+{
+ "packages": [
+ {
+ "name": "a/a", "version": "1.0.0",
+ "source": { "reference": "new-git-ref", "type": "git", "url": "new-git-url" },
+ "type": "library"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": []
+}
+--EXPECT--
+
diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php
index 7fa85d76d..5339b8ff3 100644
--- a/tests/Composer/Test/InstallerTest.php
+++ b/tests/Composer/Test/InstallerTest.php
@@ -14,7 +14,6 @@ namespace Composer\Test;
use Composer\Installer;
use Composer\Console\Application;
-use Composer\Config;
use Composer\Json\JsonFile;
use Composer\Repository\ArrayRepository;
use Composer\Repository\RepositoryManager;
@@ -108,7 +107,7 @@ class InstallerTest extends TestCase
$a,
new ArrayRepository(array($b)),
array(
- 'install' => array($b)
+ 'install' => array($b),
),
);
@@ -128,7 +127,7 @@ class InstallerTest extends TestCase
$a,
new ArrayRepository(array($a, $b)),
array(
- 'install' => array($b)
+ 'install' => array($b),
),
);
@@ -191,7 +190,8 @@ class InstallerTest extends TestCase
}));
}
- $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), md5(json_encode($composerConfig)));
+ $contents = json_encode($composerConfig);
+ $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents);
$composer->setLocker($locker);
$eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
@@ -237,6 +237,7 @@ class InstallerTest extends TestCase
if ($expectLock) {
unset($actualLock['hash']);
+ unset($actualLock['content-hash']);
unset($actualLock['_readme']);
$this->assertEquals($expectLock, $actualLock);
}
diff --git a/tests/Composer/Test/Json/ComposerSchemaTest.php b/tests/Composer/Test/Json/ComposerSchemaTest.php
index 1b8805f48..51949797c 100644
--- a/tests/Composer/Test/Json/ComposerSchemaTest.php
+++ b/tests/Composer/Test/Json/ComposerSchemaTest.php
@@ -23,18 +23,18 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
{
$json = '{ }';
$this->assertEquals(array(
- array('property' => '', 'message' => 'the property name is required'),
- array('property' => '', 'message' => 'the property description is required'),
+ array('property' => 'name', 'message' => 'The property name is required'),
+ array('property' => 'description', 'message' => 'The property description is required'),
), $this->check($json));
$json = '{ "name": "vendor/package" }';
$this->assertEquals(array(
- array('property' => '', 'message' => 'the property description is required'),
+ array('property' => 'description', 'message' => 'The property description is required'),
), $this->check($json));
$json = '{ "description": "generic description" }';
$this->assertEquals(array(
- array('property' => '', 'message' => 'the property name is required'),
+ array('property' => 'name', 'message' => 'The property name is required'),
), $this->check($json));
}
@@ -44,7 +44,7 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(
array(
'property' => 'minimum-stability',
- 'message' => 'does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
+ 'message' => 'Does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$',
),
), $this->check($json), 'empty string');
@@ -52,7 +52,7 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(
array(
'property' => 'minimum-stability',
- 'message' => 'does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
+ 'message' => 'Does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$',
),
), $this->check($json), 'dummy');
diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php
index 279ccd939..867c69307 100644
--- a/tests/Composer/Test/Json/JsonFileTest.php
+++ b/tests/Composer/Test/Json/JsonFileTest.php
@@ -54,6 +54,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
public function testParseErrorDetectSingleQuotes()
{
+ if (defined('JSON_PARSER_NOTSTRICT')) {
+ $this->markTestSkipped('jsonc issue, see https://github.com/remicollet/pecl-json-c/issues/23');
+ }
$json = '{
\'foo\': "bar"
}';
diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php
index 0e974ad35..fd6d49584 100644
--- a/tests/Composer/Test/Json/JsonManipulatorTest.php
+++ b/tests/Composer/Test/Json/JsonManipulatorTest.php
@@ -38,7 +38,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
" \"require\": {\n".
" \"vendor/baz\": \"qux\"\n".
" }\n".
-"}\n"
+"}\n",
),
array(
'{
@@ -53,7 +53,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -68,7 +68,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -87,7 +87,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -107,7 +107,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -127,7 +127,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -159,7 +159,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}]
}
-'
+',
),
array(
'{
@@ -188,7 +188,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"foo": "qux"
}
}
-'
+',
),
array(
'{
@@ -207,7 +207,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"foo": "qux"
}
}
-'
+',
),
array(
'{
@@ -229,7 +229,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"foo": "qux"
}
}
-'
+',
),
array(
'{
@@ -277,7 +277,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"foo": "qux"
}
}
-'
+',
),
);
}
@@ -311,7 +311,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"vendor/baz": "qux"
}
}
-'
+',
),
array(
'{
@@ -329,7 +329,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"foo": "bar"
}
}
-'
+',
),
array(
'{
@@ -401,7 +401,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on simple ones last' => array(
'{
@@ -426,7 +426,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on simple ones unique' => array(
'{
@@ -443,7 +443,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"repositories": {
}
}
-'
+',
),
'works on simple ones middle' => array(
'{
@@ -476,7 +476,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on undefined ones' => array(
'{
@@ -497,7 +497,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on child having unmatched name' => array(
'{
@@ -518,7 +518,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on child having duplicate name' => array(
'{
@@ -541,7 +541,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}
}
-'
+',
),
'works on empty repos' => array(
'{
@@ -549,19 +549,19 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}',
'bar',
- true
+ true,
),
'works on empty repos2' => array(
'{
"repositories": {}
}',
'bar',
- true
+ true,
),
'works on missing repos' => array(
"{\n}",
'bar',
- true
+ true,
),
'works on deep repos' => array(
'{
@@ -577,7 +577,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
"repositories": {
}
}
-'
+',
),
'fails on deep repos with borked texts' => array(
'{
@@ -588,7 +588,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}',
'bar',
- false
+ false,
),
'fails on deep repos with borked texts2' => array(
'{
@@ -599,7 +599,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
}
}',
'bar',
- false
+ false,
),
'fails on deep arrays with borked texts' => array(
'{
@@ -610,7 +610,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
]
}',
'bar',
- false
+ false,
),
'fails on deep arrays with borked texts2' => array(
'{
@@ -621,7 +621,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
]
}',
'bar',
- false
+ false,
),
);
}
diff --git a/tests/Composer/Test/Json/JsonValidationExceptionTest.php b/tests/Composer/Test/Json/JsonValidationExceptionTest.php
index 76959d688..31ba9b7bf 100644
--- a/tests/Composer/Test/Json/JsonValidationExceptionTest.php
+++ b/tests/Composer/Test/Json/JsonValidationExceptionTest.php
@@ -36,7 +36,7 @@ class JsonValidationExceptionTest extends \PHPUnit_Framework_TestCase
{
return array(
array('test message', array()),
- array(null, null)
+ array(null, null),
);
}
}
diff --git a/tests/Composer/Test/Mock/ProcessExecutorMock.php b/tests/Composer/Test/Mock/ProcessExecutorMock.php
deleted file mode 100644
index 13ea9792b..000000000
--- a/tests/Composer/Test/Mock/ProcessExecutorMock.php
+++ /dev/null
@@ -1,31 +0,0 @@
-
- * Jordi Boggiano
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Test\Mock;
-
-use Composer\Util\ProcessExecutor;
-
-class ProcessExecutorMock extends ProcessExecutor
-{
- private $execute;
-
- public function __construct(\Closure $execute)
- {
- $this->execute = $execute;
- }
-
- public function execute($command, &$output = null, $cwd = null)
- {
- $execute = $this->execute;
-
- return $execute($command, $output, $cwd);
- }
-}
diff --git a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php
index e9233f3cb..f395eba6e 100644
--- a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php
+++ b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php
@@ -14,7 +14,6 @@ namespace Composer\Test\Package\Archiver;
use Composer\Package\Archiver\ArchivableFilesFinder;
use Composer\Util\Filesystem;
-
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ExecutableFinder;
@@ -75,7 +74,8 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
'parameters.yml',
'parameters.yml.dist',
'!important!.txt',
- '!important_too!.txt'
+ '!important_too!.txt',
+ '#weirdfile',
);
foreach ($fileTree as $relativePath) {
@@ -98,7 +98,7 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
'!/prefixB.foo',
'/prefixA.foo',
'prefixC.*',
- '!*/*/*/prefixC.foo'
+ '!*/*/*/prefixC.foo',
);
$this->finder = new ArchivableFilesFinder($this->sources, $excludes);
@@ -106,6 +106,7 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
$this->assertArchivableFiles(array(
'/!important!.txt',
'/!important_too!.txt',
+ '/#weirdfile',
'/A/prefixA.foo',
'/A/prefixD.foo',
'/A/prefixE.foo',
@@ -170,7 +171,8 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
'H/**',
'J/',
'parameters.yml',
- '\!important!.txt'
+ '\!important!.txt',
+ '\#*',
)));
// git does not currently support negative git attributes
@@ -181,7 +183,7 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
//'!/prefixB.foo export-ignore',
'/prefixA.foo export-ignore',
'prefixC.* export-ignore',
- //'!/*/*/prefixC.foo export-ignore'
+ //'!/*/*/prefixC.foo export-ignore',
)));
$this->finder = new ArchivableFilesFinder($this->sources, array());
@@ -284,7 +286,7 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
*
* @param string $process The name of the binary to test.
*
- * @return boolean True if the process is available, false otherwise.
+ * @return bool True if the process is available, false otherwise.
*/
protected function isProcessAvailable($process)
{
diff --git a/tests/Composer/Test/Package/Archiver/GitExcludeFilterTest.php b/tests/Composer/Test/Package/Archiver/GitExcludeFilterTest.php
index 97c02c8e6..0a19a1327 100644
--- a/tests/Composer/Test/Package/Archiver/GitExcludeFilterTest.php
+++ b/tests/Composer/Test/Package/Archiver/GitExcludeFilterTest.php
@@ -29,8 +29,8 @@ class GitExcludeFilterTest extends \PHPUnit_Framework_TestCase
public function patterns()
{
return array(
- array('app/config/parameters.yml', array('#(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)#', false, false)),
- array('!app/config/parameters.yml', array('#(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)#', true, false)),
+ array('app/config/parameters.yml', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', false, false)),
+ array('!app/config/parameters.yml', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', true, false)),
);
}
}
diff --git a/tests/Composer/Test/Package/BasePackageTest.php b/tests/Composer/Test/Package/BasePackageTest.php
index 1fe0ece84..c54762fca 100644
--- a/tests/Composer/Test/Package/BasePackageTest.php
+++ b/tests/Composer/Test/Package/BasePackageTest.php
@@ -39,4 +39,51 @@ class BasePackageTest extends \PHPUnit_Framework_TestCase
$package->setRepository($this->getMock('Composer\Repository\RepositoryInterface'));
$package->setRepository($this->getMock('Composer\Repository\RepositoryInterface'));
}
+
+ /**
+ * @dataProvider formattedVersions
+ */
+ public function testFormatVersionForDevPackage(BasePackage $package, $truncate, $expected)
+ {
+ $this->assertSame($expected, $package->getFullPrettyVersion($truncate));
+ }
+
+ public function formattedVersions()
+ {
+ $data = array(
+ array(
+ 'sourceReference' => 'v2.1.0-RC2',
+ 'truncate' => true,
+ 'expected' => 'PrettyVersion v2.1.0-RC2',
+ ),
+ array(
+ 'sourceReference' => 'bbf527a27356414bfa9bf520f018c5cb7af67c77',
+ 'truncate' => true,
+ 'expected' => 'PrettyVersion bbf527a',
+ ),
+ array(
+ 'sourceReference' => 'v1.0.0',
+ 'truncate' => false,
+ 'expected' => 'PrettyVersion v1.0.0',
+ ),
+ array(
+ 'sourceReference' => 'bbf527a27356414bfa9bf520f018c5cb7af67c77',
+ 'truncate' => false,
+ 'expected' => 'PrettyVersion bbf527a27356414bfa9bf520f018c5cb7af67c77',
+ ),
+ );
+
+ $self = $this;
+ $createPackage = function ($arr) use ($self) {
+ $package = $self->getMockForAbstractClass('\Composer\Package\BasePackage', array(), '', false);
+ $package->expects($self->once())->method('isDev')->will($self->returnValue(true));
+ $package->expects($self->once())->method('getSourceType')->will($self->returnValue('git'));
+ $package->expects($self->once())->method('getPrettyVersion')->will($self->returnValue('PrettyVersion'));
+ $package->expects($self->any())->method('getSourceReference')->will($self->returnValue($arr['sourceReference']));
+
+ return array($package, $arr['truncate'], $arr['expected']);
+ };
+
+ return array_map($createPackage, $data);
+ }
}
diff --git a/tests/Composer/Test/Package/CompletePackageTest.php b/tests/Composer/Test/Package/CompletePackageTest.php
index de119ebaa..aa3127071 100644
--- a/tests/Composer/Test/Package/CompletePackageTest.php
+++ b/tests/Composer/Test/Package/CompletePackageTest.php
@@ -13,7 +13,7 @@
namespace Composer\Test\Package;
use Composer\Package\Package;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
use Composer\TestCase;
class CompletePackageTest extends TestCase
diff --git a/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php b/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php
index c9aa2b8a0..c2c820fb1 100644
--- a/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php
+++ b/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php
@@ -14,7 +14,7 @@ namespace Composer\Test\Package\Dumper;
use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\Link;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
class ArrayDumperTest extends \PHPUnit_Framework_TestCase
{
@@ -45,7 +45,7 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
array(
'name' => 'foo',
'version' => '1.0',
- 'version_normalized' => '1.0.0.0'
+ 'version_normalized' => '1.0.0.0',
),
$config
);
@@ -100,7 +100,7 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
return array(
array(
'type',
- 'library'
+ 'library',
),
array(
'time',
@@ -110,46 +110,46 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
),
array(
'authors',
- array('Nils Adermann ', 'Jordi Boggiano ')
+ array('Nils Adermann ', 'Jordi Boggiano '),
),
array(
'homepage',
- 'https://getcomposer.org'
+ 'https://getcomposer.org',
),
array(
'description',
- 'Dependency Manager'
+ 'Dependency Manager',
),
array(
'keywords',
array('package', 'dependency', 'autoload'),
null,
- array('autoload', 'dependency', 'package')
+ array('autoload', 'dependency', 'package'),
),
array(
'bin',
array('bin/composer'),
- 'binaries'
+ 'binaries',
),
array(
'license',
- array('MIT')
+ array('MIT'),
),
array(
'autoload',
- array('psr-0' => array('Composer' => 'src/'))
+ array('psr-0' => array('Composer' => 'src/')),
),
array(
'repositories',
- array('packagist' => false)
+ array('packagist' => false),
),
array(
'scripts',
- array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate')
+ array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate'),
),
array(
'extra',
- array('class' => 'MyVendor\\Installer')
+ array('class' => 'MyVendor\\Installer'),
),
array(
'archive',
@@ -161,20 +161,20 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
),
array(
'require',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'requires',
array('foo/bar' => '1.0.0'),
),
array(
'require-dev',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires (for development)', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires (for development)', '1.0.0')),
'devRequires',
array('foo/bar' => '1.0.0'),
),
array(
'suggest',
array('foo/bar' => 'very useful package'),
- 'suggests'
+ 'suggests',
),
array(
'support',
@@ -182,45 +182,45 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
),
array(
'require',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'requires',
- array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0')
+ array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0'),
),
array(
'require-dev',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'devRequires',
- array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0')
+ array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0'),
),
array(
'suggest',
array('foo/bar' => 'very useful package', 'bar/baz' => 'another useful package'),
'suggests',
- array('bar/baz' => 'another useful package', 'foo/bar' => 'very useful package')
+ array('bar/baz' => 'another useful package', 'foo/bar' => 'very useful package'),
),
array(
'provide',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'provides',
- array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0')
+ array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0'),
),
array(
'replace',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'replaces',
- array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0')
+ array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0'),
),
array(
'conflict',
- array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')),
+ array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),
'conflicts',
- array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0')
+ array('bar/baz' => '1.0.0', 'foo/bar' => '1.0.0'),
),
array(
'transport-options',
array('ssl' => array('local_cert' => '/opt/certs/test.pem')),
- 'transportOptions'
- )
+ 'transportOptions',
+ ),
);
}
diff --git a/tests/Composer/Test/Package/LinkConstraint/MultiConstraintTest.php b/tests/Composer/Test/Package/LinkConstraint/MultiConstraintTest.php
deleted file mode 100644
index 892b7fef7..000000000
--- a/tests/Composer/Test/Package/LinkConstraint/MultiConstraintTest.php
+++ /dev/null
@@ -1,54 +0,0 @@
-
- * Jordi Boggiano
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Test\Package\LinkConstraint;
-
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Package\LinkConstraint\MultiConstraint;
-
-class MultiConstraintTest extends \PHPUnit_Framework_TestCase
-{
- public function testMultiVersionMatchSucceeds()
- {
- $versionRequireStart = new VersionConstraint('>', '1.0');
- $versionRequireEnd = new VersionConstraint('<', '1.2');
- $versionProvide = new VersionConstraint('==', '1.1');
-
- $multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
-
- $this->assertTrue($multiRequire->matches($versionProvide));
- }
-
- public function testMultiVersionProvidedMatchSucceeds()
- {
- $versionRequireStart = new VersionConstraint('>', '1.0');
- $versionRequireEnd = new VersionConstraint('<', '1.2');
- $versionProvideStart = new VersionConstraint('>=', '1.1');
- $versionProvideEnd = new VersionConstraint('<', '2.0');
-
- $multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
- $multiProvide = new MultiConstraint(array($versionProvideStart, $versionProvideEnd));
-
- $this->assertTrue($multiRequire->matches($multiProvide));
- }
-
- public function testMultiVersionMatchFails()
- {
- $versionRequireStart = new VersionConstraint('>', '1.0');
- $versionRequireEnd = new VersionConstraint('<', '1.2');
- $versionProvide = new VersionConstraint('==', '1.2');
-
- $multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
-
- $this->assertFalse($multiRequire->matches($versionProvide));
- }
-}
diff --git a/tests/Composer/Test/Package/LinkConstraint/VersionConstraintTest.php b/tests/Composer/Test/Package/LinkConstraint/VersionConstraintTest.php
deleted file mode 100644
index e2adda282..000000000
--- a/tests/Composer/Test/Package/LinkConstraint/VersionConstraintTest.php
+++ /dev/null
@@ -1,105 +0,0 @@
-
- * Jordi Boggiano
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Test\Package\LinkConstraint;
-
-use Composer\Package\LinkConstraint\VersionConstraint;
-
-class VersionConstraintTest extends \PHPUnit_Framework_TestCase
-{
- public static function successfulVersionMatches()
- {
- return array(
- // require provide
- array('==', '1', '==', '1'),
- array('>=', '1', '>=', '2'),
- array('>=', '2', '>=', '1'),
- array('>=', '2', '>', '1'),
- array('<=', '2', '>=', '1'),
- array('>=', '1', '<=', '2'),
- array('==', '2', '>=', '2'),
- array('!=', '1', '!=', '1'),
- array('!=', '1', '==', '2'),
- array('!=', '1', '<', '1'),
- array('!=', '1', '<=', '1'),
- array('!=', '1', '>', '1'),
- array('!=', '1', '>=', '1'),
- array('==', 'dev-foo-bar', '==', 'dev-foo-bar'),
- array('==', 'dev-foo-xyz', '==', 'dev-foo-xyz'),
- array('>=', 'dev-foo-bar', '>=', 'dev-foo-xyz'),
- array('<=', 'dev-foo-bar', '<', 'dev-foo-xyz'),
- array('!=', 'dev-foo-bar', '<', 'dev-foo-xyz'),
- array('>=', 'dev-foo-bar', '!=', 'dev-foo-bar'),
- array('!=', 'dev-foo-bar', '!=', 'dev-foo-xyz'),
- );
- }
-
- /**
- * @dataProvider successfulVersionMatches
- */
- public function testVersionMatchSucceeds($requireOperator, $requireVersion, $provideOperator, $provideVersion)
- {
- $versionRequire = new VersionConstraint($requireOperator, $requireVersion);
- $versionProvide = new VersionConstraint($provideOperator, $provideVersion);
-
- $this->assertTrue($versionRequire->matches($versionProvide));
- }
-
- public static function failingVersionMatches()
- {
- return array(
- // require provide
- array('==', '1', '==', '2'),
- array('>=', '2', '<=', '1'),
- array('>=', '2', '<', '2'),
- array('<=', '2', '>', '2'),
- array('>', '2', '<=', '2'),
- array('<=', '1', '>=', '2'),
- array('>=', '2', '<=', '1'),
- array('==', '2', '<', '2'),
- array('!=', '1', '==', '1'),
- array('==', '1', '!=', '1'),
- array('==', 'dev-foo-dist', '==', 'dev-foo-zist'),
- array('==', 'dev-foo-bist', '==', 'dev-foo-aist'),
- array('<=', 'dev-foo-bist', '>=', 'dev-foo-aist'),
- array('>=', 'dev-foo-bist', '<', 'dev-foo-aist'),
- array('<', '0.12', '==', 'dev-foo'), // branches are not comparable
- array('>', '0.12', '==', 'dev-foo'), // branches are not comparable
- );
- }
-
- /**
- * @dataProvider failingVersionMatches
- */
- public function testVersionMatchFails($requireOperator, $requireVersion, $provideOperator, $provideVersion)
- {
- $versionRequire = new VersionConstraint($requireOperator, $requireVersion);
- $versionProvide = new VersionConstraint($provideOperator, $provideVersion);
-
- $this->assertFalse($versionRequire->matches($versionProvide));
- }
-
- public function testComparableBranches()
- {
- $versionRequire = new VersionConstraint('>', '0.12');
- $versionProvide = new VersionConstraint('==', 'dev-foo');
-
- $this->assertFalse($versionRequire->matches($versionProvide));
- $this->assertFalse($versionRequire->matchSpecific($versionProvide, true));
-
- $versionRequire = new VersionConstraint('<', '0.12');
- $versionProvide = new VersionConstraint('==', 'dev-foo');
-
- $this->assertFalse($versionRequire->matches($versionProvide));
- $this->assertTrue($versionRequire->matchSpecific($versionProvide, true));
- }
-}
diff --git a/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php
index 1491571a1..10963b55b 100644
--- a/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php
+++ b/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php
@@ -17,6 +17,11 @@ use Composer\Package\Dumper\ArrayDumper;
class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
{
+ /**
+ * @var ArrayLoader
+ */
+ private $loader;
+
public function setUp()
{
$this->loader = new ArrayLoader(null, true);
@@ -118,7 +123,7 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
'exclude' => array('/foo/bar', 'baz', '!/foo/bar/baz'),
),
'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem')),
- 'abandoned' => 'foo/bar'
+ 'abandoned' => 'foo/bar',
);
$package = $this->loader->load($config);
@@ -189,7 +194,7 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
$config = array(
'name' => 'A',
'version' => '1.2.3.4',
- 'abandoned' => 'foo/bar'
+ 'abandoned' => 'foo/bar',
);
$package = $this->loader->load($config);
@@ -201,10 +206,50 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
{
$config = array(
'name' => 'A',
- 'version' => '1.2.3.4'
+ 'version' => '1.2.3.4',
);
$package = $this->loader->load($config);
$this->assertFalse($package->isAbandoned());
}
+
+ public function pluginApiVersions()
+ {
+ return array(
+ array('1.0'),
+ array('1.0.0'),
+ array('1.0.0.0'),
+ array('1'),
+ array('=1.0.0'),
+ array('==1.0'),
+ array('~1.0.0'),
+ array('*'),
+ array('3.0.*'),
+ array('@stable'),
+ array('1.0.0@stable'),
+ array('^5.1'),
+ array('>=1.0.0 <2.5'),
+ array('x'),
+ array('1.0.0-dev'),
+ );
+ }
+
+ /**
+ * @dataProvider pluginApiVersions
+ */
+ public function testPluginApiVersionAreKeptAsDeclared($apiVersion)
+ {
+ $links = $this->loader->parseLinks('Plugin', '9.9.9', '', array('composer-plugin-api' => $apiVersion));
+
+ $this->assertArrayHasKey('composer-plugin-api', $links);
+ $this->assertSame($apiVersion, $links['composer-plugin-api']->getConstraint()->getPrettyString());
+ }
+
+ public function testPluginApiVersionDoesSupportSelfVersion()
+ {
+ $links = $this->loader->parseLinks('Plugin', '6.6.6', '', array('composer-plugin-api' => 'self.version'));
+
+ $this->assertArrayHasKey('composer-plugin-api', $links);
+ $this->assertSame('6.6.6', $links['composer-plugin-api']->getConstraint()->getPrettyString());
+ }
}
diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
index 37c259676..218d6e5ff 100644
--- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
+++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
@@ -15,144 +15,17 @@ namespace Composer\Test\Package\Loader;
use Composer\Config;
use Composer\Package\Loader\RootPackageLoader;
use Composer\Package\BasePackage;
-use Composer\Test\Mock\ProcessExecutorMock;
-use Composer\Repository\RepositoryManager;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Semver\VersionParser;
class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
{
- public function testDetachedHeadBecomesDevHash()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea';
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $self = $this;
-
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self, $commitHash) {
- if (0 === strpos($command, 'git describe')) {
- // simulate not being on a tag
- return 1;
- }
-
- $self->assertStringStartsWith('git branch', $command);
-
- $output = "* (no branch) $commitHash Commit message\n";
-
- return 0;
- });
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
- $package = $loader->load(array());
-
- $this->assertEquals("dev-$commitHash", $package->getVersion());
- }
-
- public function testTagBecomesVersion()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $self = $this;
-
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) {
- $self->assertEquals('git describe --exact-match --tags', $command);
-
- $output = "v2.0.5-alpha2";
-
- return 0;
- });
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
- $package = $loader->load(array());
-
- $this->assertEquals("2.0.5.0-alpha2", $package->getVersion());
- }
-
- public function testInvalidTagBecomesVersion()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $self = $this;
-
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) {
- if ('git describe --exact-match --tags' === $command) {
- $output = "foo-bar";
-
- return 0;
- }
-
- $output = "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n";
-
- return 0;
- });
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
- $package = $loader->load(array());
-
- $this->assertEquals("dev-foo", $package->getVersion());
- }
-
- public function testNoVersionIsVisibleInPrettyVersion()
- {
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $self = $this;
-
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')
- ->disableOriginalConstructor()
- ->getMock();
- $processExecutor->expects($this->any())
- ->method('execute')
- ->willReturn(null);
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
- $package = $loader->load(array());
-
- $this->assertEquals("1.0.0.0", $package->getVersion());
- $this->assertEquals("No version set (parsed as 1.0.0)", $package->getPrettyVersion());
- }
-
protected function loadPackage($data)
{
$manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
->disableOriginalConstructor()
->getMock();
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) {
- return 1;
- });
-
$config = new Config;
$config->merge(array('repositories' => array('packagist' => false)));
@@ -168,7 +41,7 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
'foo/bar' => '~2.1.0-beta2',
'bar/baz' => '1.0.x-dev as 1.2.0',
'qux/quux' => '1.0.*@rc',
- 'zux/complex' => '~1.0,>=1.0.2@dev'
+ 'zux/complex' => '~1.0,>=1.0.2@dev',
),
'minimum-stability' => 'alpha',
));
@@ -181,6 +54,35 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
), $package->getStabilityFlags());
}
+ public function testNoVersionIsVisibleInPrettyVersion()
+ {
+ $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor
+ ->expects($this->any())
+ ->method('execute')
+ ->willReturn(null)
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser()));
+ $package = $loader->load(array());
+
+ $this->assertEquals("1.0.0.0", $package->getVersion());
+ $this->assertEquals("No version set (parsed as 1.0.0)", $package->getPrettyVersion());
+ }
+
public function testFeatureBranchPrettyVersion()
{
if (!function_exists('proc_open')) {
@@ -189,32 +91,53 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
$manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
$self = $this;
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) {
- if (0 === strpos($command, 'git rev-list')) {
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+
+ return 1;
+ })
+ ;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n";
+
+ return 0;
+ })
+ ;
+
+ $executor
+ ->expects($this->at(2))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git rev-list master..latest-production', $command);
$output = "";
return 0;
- }
-
- if ('git branch --no-color --no-abbrev -v' !== $command) {
- return 1; //0;
- }
-
- $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
-
- $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n";
-
- return 0;
- });
+ })
+ ;
$config = new Config;
$config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser()));
$package = $loader->load(array('require' => array('foo/bar' => 'self.version')));
$this->assertEquals("dev-master", $package->getPrettyVersion());
@@ -228,32 +151,42 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
$manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
$self = $this;
- /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */
- $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) {
- if (0 === strpos($command, 'git rev-list')) {
- $output = "";
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+
+ return 1;
+ })
+ ;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n";
return 0;
- }
-
- if ('git branch --no-color --no-abbrev -v' !== $command) {
- return 1; //0;
- }
-
- $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
-
- $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n";
-
- return 0;
- });
+ })
+ ;
$config = new Config;
$config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $processExecutor);
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser()));
$package = $loader->load(array('require' => array('foo/bar' => 'self.version'), "non-feature-branches" => array("latest-.*")));
$this->assertEquals("dev-latest-production", $package->getPrettyVersion());
diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php
index 075ee8253..4668099bf 100644
--- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php
+++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php
@@ -12,7 +12,6 @@
namespace Composer\Test\Package\Loader;
-use Composer\Package;
use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Package\Loader\InvalidPackageException;
@@ -119,7 +118,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
array(
'type' => 'composer',
'url' => 'https://packagist.org/',
- )
+ ),
),
'config' => array(
'bin-dir' => 'bin',
@@ -140,14 +139,14 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'branch-alias' => array(
'dev-master' => '2.0-dev',
'dev-old' => '1.0.x-dev',
- '3.x-dev' => '3.1.x-dev'
+ '3.x-dev' => '3.1.x-dev',
),
),
'bin' => array(
'bin/foo',
'bin/bar',
),
- 'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem'))
+ 'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem')),
),
),
array( // test as array
@@ -221,8 +220,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'name' => 'foo',
),
array(
- 'name : invalid value (foo), must match [A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*'
- )
+ 'name : invalid value (foo), must match [A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*',
+ ),
),
array(
array(
@@ -231,7 +230,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
),
array(
'homepage : should be a string, integer given',
- )
+ ),
),
array(
array(
@@ -242,7 +241,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
),
array(
'support.source : invalid value, must be a string',
- )
+ ),
),
array(
array(
@@ -250,8 +249,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'autoload' => 'strings',
),
array(
- 'autoload : should be an array, string given'
- )
+ 'autoload : should be an array, string given',
+ ),
),
array(
array(
@@ -263,8 +262,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
),
),
array(
- 'autoload : invalid value (psr0), must be one of psr-0, psr-4, classmap, files'
- )
+ 'autoload : invalid value (psr0), must be one of psr-0, psr-4, classmap, files',
+ ),
),
array(
array(
@@ -272,8 +271,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'transport-options' => 'test',
),
array(
- 'transport-options : should be an array, string given'
- )
+ 'transport-options : should be an array, string given',
+ ),
),
);
}
@@ -287,8 +286,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'homepage' => 'foo:bar',
),
array(
- 'homepage : invalid value (foo:bar), must be an http/https URL'
- )
+ 'homepage : invalid value (foo:bar), must be an http/https URL',
+ ),
),
array(
array(
@@ -305,7 +304,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'support.forum : invalid value (foo:bar), must be an http/https URL',
'support.issues : invalid value (foo:bar), must be an http/https URL',
'support.wiki : invalid value (foo:bar), must be an http/https URL',
- )
+ ),
),
array(
array(
@@ -323,35 +322,35 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'require.bar/foo : unbound version constraints (dev-master) should be avoided',
'require.bar/hacked : unbound version constraints (@stable) should be avoided',
),
- false
+ false,
),
array(
array(
'name' => 'foo/bar',
'extra' => array(
'branch-alias' => array(
- '5.x-dev' => '3.1.x-dev'
+ '5.x-dev' => '3.1.x-dev',
),
- )
+ ),
),
array(
- 'extra.branch-alias.5.x-dev : the target branch (3.1.x-dev) is not a valid numeric alias for this version'
+ 'extra.branch-alias.5.x-dev : the target branch (3.1.x-dev) is not a valid numeric alias for this version',
),
- false
+ false,
),
array(
array(
'name' => 'foo/bar',
'extra' => array(
'branch-alias' => array(
- '5.x-dev' => '3.1-dev'
+ '5.x-dev' => '3.1-dev',
),
- )
+ ),
),
array(
- 'extra.branch-alias.5.x-dev : the target branch (3.1-dev) is not a valid numeric alias for this version'
+ 'extra.branch-alias.5.x-dev : the target branch (3.1-dev) is not a valid numeric alias for this version',
),
- false
+ false,
),
);
}
diff --git a/tests/Composer/Test/Package/LockerTest.php b/tests/Composer/Test/Package/LockerTest.php
index 914bbe2f9..79f82e74d 100644
--- a/tests/Composer/Test/Package/LockerTest.php
+++ b/tests/Composer/Test/Package/LockerTest.php
@@ -20,7 +20,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
public function testIsLocked()
{
$json = $this->createJsonFileMock();
- $locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(), 'md5');
+ $locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(),
+ $this->getJsonContent());
$json
->expects($this->any())
@@ -40,7 +41,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json
->expects($this->once())
@@ -58,7 +59,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json
->expects($this->once())
@@ -70,8 +71,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue(array(
'packages' => array(
array('name' => 'pkg1', 'version' => '1.0.0-beta'),
- array('name' => 'pkg2', 'version' => '0.1.10')
- )
+ array('name' => 'pkg2', 'version' => '0.1.10'),
+ ),
)));
$repo = $locker->getLockedRepository();
@@ -85,7 +86,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $jsonContent = $this->getJsonContent() . ' ';
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
$package1 = $this->createPackageMock();
$package2 = $this->createPackageMock();
@@ -116,17 +118,21 @@ class LockerTest extends \PHPUnit_Framework_TestCase
->method('getVersion')
->will($this->returnValue('0.1.10.0'));
+ $hash = md5($jsonContent);
+ $contentHash = md5(trim($jsonContent));
+
$json
->expects($this->once())
->method('write')
->with(array(
'_readme' => array('This file locks the dependencies of your project to a known state',
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
- 'This file is @gener'.'ated automatically'),
- 'hash' => 'md5',
+ 'This file is @gener'.'ated automatically', ),
+ 'hash' => $hash,
+ 'content-hash' => $contentHash,
'packages' => array(
array('name' => 'pkg1', 'version' => '1.0.0-beta'),
- array('name' => 'pkg2', 'version' => '0.1.10')
+ array('name' => 'pkg2', 'version' => '0.1.10'),
),
'packages-dev' => array(),
'aliases' => array(),
@@ -148,7 +154,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$package1 = $this->createPackageMock();
$package1
@@ -167,12 +173,13 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $jsonContent = $this->getJsonContent();
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
$json
->expects($this->once())
->method('read')
- ->will($this->returnValue(array('hash' => 'md5')));
+ ->will($this->returnValue(array('hash' => md5($jsonContent))));
$this->assertTrue($locker->isFresh());
}
@@ -183,12 +190,47 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
- $locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json
->expects($this->once())
->method('read')
- ->will($this->returnValue(array('hash' => 'oldmd5')));
+ ->will($this->returnValue(array('hash' => $this->getJsonContent(array('name' => 'test2')))));
+
+ $this->assertFalse($locker->isFresh());
+ }
+
+ public function testIsFreshWithContentHash()
+ {
+ $json = $this->createJsonFileMock();
+ $repo = $this->createRepositoryManagerMock();
+ $inst = $this->createInstallationManagerMock();
+
+ $jsonContent = $this->getJsonContent();
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
+
+ $json
+ ->expects($this->once())
+ ->method('read')
+ ->will($this->returnValue(array('hash' => md5($jsonContent . ' '), 'content-hash' => md5($jsonContent))));
+
+ $this->assertTrue($locker->isFresh());
+ }
+
+ public function testIsFreshFalseWithContentHash()
+ {
+ $json = $this->createJsonFileMock();
+ $repo = $this->createRepositoryManagerMock();
+ $inst = $this->createInstallationManagerMock();
+
+ $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
+
+ $differentHash = md5($this->getJsonContent(array('name' => 'test2')));
+
+ $json
+ ->expects($this->once())
+ ->method('read')
+ ->will($this->returnValue(array('hash' => $differentHash, 'content-hash' => $differentHash)));
$this->assertFalse($locker->isFresh());
}
@@ -227,4 +269,16 @@ class LockerTest extends \PHPUnit_Framework_TestCase
return $this->getMockBuilder('Composer\Package\PackageInterface')
->getMock();
}
+
+ private function getJsonContent(array $customData = array())
+ {
+ $data = array_merge(array(
+ 'minimum-stability' => 'beta',
+ 'name' => 'test',
+ ), $customData);
+
+ ksort($data);
+
+ return json_encode($data);
+ }
}
diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php
new file mode 100644
index 000000000..84da8d2e9
--- /dev/null
+++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php
@@ -0,0 +1,137 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Test\Package\Version;
+
+use Composer\Config;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Semver\VersionParser;
+
+class VersionGuesserTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ if (!function_exists('proc_open')) {
+ $this->markTestSkipped('proc_open() is not available');
+ }
+ }
+
+ public function testDetachedHeadBecomesDevHash()
+ {
+ $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea';
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->with('git describe --exact-match --tags')
+ ->willReturn(1)
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* (no branch) $commitHash Commit message\n";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($config, $executor, new VersionParser());
+ $version = $guesser->guessVersion(array(), 'dummy/path');
+
+ $this->assertEquals("dev-$commitHash", $version);
+ }
+
+ public function testTagBecomesVersion()
+ {
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+ $output = "v2.0.5-alpha2";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($config, $executor, new VersionParser());
+ $version = $guesser->guessVersion(array(), 'dummy/path');
+
+ $this->assertEquals("2.0.5.0-alpha2", $version);
+ }
+
+ public function testInvalidTagBecomesVersion()
+ {
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+ $output = "foo-bar";
+
+ return 0;
+ })
+ ;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($config, $executor, new VersionParser());
+ $version = $guesser->guessVersion(array(), 'dummy/path');
+
+ $this->assertEquals("dev-foo", $version);
+ }
+}
diff --git a/tests/Composer/Test/Package/Version/VersionParserTest.php b/tests/Composer/Test/Package/Version/VersionParserTest.php
deleted file mode 100644
index 565451811..000000000
--- a/tests/Composer/Test/Package/Version/VersionParserTest.php
+++ /dev/null
@@ -1,563 +0,0 @@
-
- * Jordi Boggiano
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Test\Package\Version;
-
-use Composer\Package\Link;
-use Composer\Package\Version\VersionParser;
-use Composer\Package\LinkConstraint\MultiConstraint;
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Package\LinkConstraint\EmptyConstraint;
-use Composer\Package\PackageInterface;
-
-class VersionParserTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider formattedVersions
- */
- public function testFormatVersionForDevPackage(PackageInterface $package, $truncate, $expected)
- {
- $this->assertSame($expected, VersionParser::formatVersion($package, $truncate));
- }
-
- public function formattedVersions()
- {
- $data = array(
- array(
- 'sourceReference' => 'v2.1.0-RC2',
- 'truncate' => true,
- 'expected' => 'PrettyVersion v2.1.0-RC2'
- ),
- array(
- 'sourceReference' => 'bbf527a27356414bfa9bf520f018c5cb7af67c77',
- 'truncate' => true,
- 'expected' => 'PrettyVersion bbf527a'
- ),
- array(
- 'sourceReference' => 'v1.0.0',
- 'truncate' => false,
- 'expected' => 'PrettyVersion v1.0.0'
- ),
- array(
- 'sourceReference' => 'bbf527a27356414bfa9bf520f018c5cb7af67c77',
- 'truncate' => false,
- 'expected' => 'PrettyVersion bbf527a27356414bfa9bf520f018c5cb7af67c77'
- ),
- );
-
- $self = $this;
- $createPackage = function ($arr) use ($self) {
- $package = $self->getMock('\Composer\Package\PackageInterface');
- $package->expects($self->once())->method('isDev')->will($self->returnValue(true));
- $package->expects($self->once())->method('getSourceType')->will($self->returnValue('git'));
- $package->expects($self->once())->method('getPrettyVersion')->will($self->returnValue('PrettyVersion'));
- $package->expects($self->any())->method('getSourceReference')->will($self->returnValue($arr['sourceReference']));
-
- return array($package, $arr['truncate'], $arr['expected']);
- };
-
- return array_map($createPackage, $data);
- }
-
- /**
- * @dataProvider numericAliasVersions
- */
- public function testParseNumericAliasPrefix($input, $expected)
- {
- $parser = new VersionParser;
- $this->assertSame($expected, $parser->parseNumericAliasPrefix($input));
- }
-
- public function numericAliasVersions()
- {
- return array(
- array('0.x-dev', '0.'),
- array('1.0.x-dev', '1.0.'),
- array('1.x-dev', '1.'),
- array('1.2.x-dev', '1.2.'),
- array('1.2-dev', '1.2.'),
- array('1-dev', '1.'),
- array('dev-develop', false),
- array('dev-master', false),
- );
- }
-
- /**
- * @dataProvider successfulNormalizedVersions
- */
- public function testNormalizeSucceeds($input, $expected)
- {
- $parser = new VersionParser;
- $this->assertSame($expected, $parser->normalize($input));
- }
-
- public function successfulNormalizedVersions()
- {
- return array(
- 'none' => array('1.0.0', '1.0.0.0'),
- 'none/2' => array('1.2.3.4', '1.2.3.4'),
- 'parses state' => array('1.0.0RC1dev', '1.0.0.0-RC1-dev'),
- 'CI parsing' => array('1.0.0-rC15-dev', '1.0.0.0-RC15-dev'),
- 'delimiters' => array('1.0.0.RC.15-dev', '1.0.0.0-RC15-dev'),
- 'RC uppercase' => array('1.0.0-rc1', '1.0.0.0-RC1'),
- 'patch replace' => array('1.0.0.pl3-dev', '1.0.0.0-patch3-dev'),
- 'forces w.x.y.z' => array('1.0-dev', '1.0.0.0-dev'),
- 'forces w.x.y.z/2' => array('0', '0.0.0.0'),
- 'parses long' => array('10.4.13-beta', '10.4.13.0-beta'),
- 'parses long/2' => array('10.4.13beta2', '10.4.13.0-beta2'),
- 'parses long/semver' => array('10.4.13beta.2', '10.4.13.0-beta2'),
- 'expand shorthand' => array('10.4.13-b', '10.4.13.0-beta'),
- 'expand shorthand2' => array('10.4.13-b5', '10.4.13.0-beta5'),
- 'strips leading v' => array('v1.0.0', '1.0.0.0'),
- 'strips v/datetime' => array('v20100102', '20100102'),
- 'parses dates y-m' => array('2010.01', '2010-01'),
- 'parses dates w/ .' => array('2010.01.02', '2010-01-02'),
- 'parses dates w/ -' => array('2010-01-02', '2010-01-02'),
- 'parses numbers' => array('2010-01-02.5', '2010-01-02-5'),
- 'parses dates y.m.Y' => array('2010.1.555', '2010.1.555.0'),
- 'parses datetime' => array('20100102-203040', '20100102-203040'),
- 'parses dt+number' => array('20100102203040-10', '20100102203040-10'),
- 'parses dt+patch' => array('20100102-203040-p1', '20100102-203040-patch1'),
- 'parses master' => array('dev-master', '9999999-dev'),
- 'parses trunk' => array('dev-trunk', '9999999-dev'),
- 'parses branches' => array('1.x-dev', '1.9999999.9999999.9999999-dev'),
- 'parses arbitrary' => array('dev-feature-foo', 'dev-feature-foo'),
- 'parses arbitrary2' => array('DEV-FOOBAR', 'dev-FOOBAR'),
- 'parses arbitrary3' => array('dev-feature/foo', 'dev-feature/foo'),
- 'ignores aliases' => array('dev-master as 1.0.0', '9999999-dev'),
- 'semver metadata' => array('dev-master+foo.bar', '9999999-dev'),
- 'semver metadata/2' => array('1.0.0-beta.5+foo', '1.0.0.0-beta5'),
- 'semver metadata/3' => array('1.0.0+foo', '1.0.0.0'),
- 'metadata w/ alias' => array('1.0.0+foo as 2.0', '1.0.0.0'),
- );
- }
-
- /**
- * @dataProvider failingNormalizedVersions
- * @expectedException UnexpectedValueException
- */
- public function testNormalizeFails($input)
- {
- $parser = new VersionParser;
- $parser->normalize($input);
- }
-
- public function failingNormalizedVersions()
- {
- return array(
- 'empty ' => array(''),
- 'invalid chars' => array('a'),
- 'invalid type' => array('1.0.0-meh'),
- 'too many bits' => array('1.0.0.0.0'),
- 'non-dev arbitrary' => array('feature-foo'),
- 'metadata w/ space' => array('1.0.0+foo bar'),
- );
- }
-
- /**
- * @dataProvider successfulNormalizedBranches
- */
- public function testNormalizeBranch($input, $expected)
- {
- $parser = new VersionParser;
- $this->assertSame((string) $expected, (string) $parser->normalizeBranch($input));
- }
-
- public function successfulNormalizedBranches()
- {
- return array(
- 'parses x' => array('v1.x', '1.9999999.9999999.9999999-dev'),
- 'parses *' => array('v1.*', '1.9999999.9999999.9999999-dev'),
- 'parses digits' => array('v1.0', '1.0.9999999.9999999-dev'),
- 'parses digits/2' => array('2.0', '2.0.9999999.9999999-dev'),
- 'parses long x' => array('v1.0.x', '1.0.9999999.9999999-dev'),
- 'parses long *' => array('v1.0.3.*', '1.0.3.9999999-dev'),
- 'parses long digits' => array('v2.4.0', '2.4.0.9999999-dev'),
- 'parses long digits/2' => array('2.4.4', '2.4.4.9999999-dev'),
- 'parses master' => array('master', '9999999-dev'),
- 'parses trunk' => array('trunk', '9999999-dev'),
- 'parses arbitrary' => array('feature-a', 'dev-feature-a'),
- 'parses arbitrary/2' => array('FOOBAR', 'dev-FOOBAR'),
- );
- }
-
- public function testParseConstraintsIgnoresStabilityFlag()
- {
- $parser = new VersionParser;
- $this->assertSame((string) new VersionConstraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0@dev'));
- }
-
- public function testParseConstraintsIgnoresReferenceOnDevVersion()
- {
- $parser = new VersionParser;
- $this->assertSame((string) new VersionConstraint('=', '1.0.9999999.9999999-dev'), (string) $parser->parseConstraints('1.0.x-dev#abcd123'));
- $this->assertSame((string) new VersionConstraint('=', '1.0.9999999.9999999-dev'), (string) $parser->parseConstraints('1.0.x-dev#trunk/@123'));
- }
-
- /**
- * @expectedException UnexpectedValueException
- */
- public function testParseConstraintsFailsOnBadReference()
- {
- $parser = new VersionParser;
- $this->assertSame((string) new VersionConstraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0#abcd123'));
- $this->assertSame((string) new VersionConstraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0#trunk/@123'));
- }
-
- /**
- * @expectedException UnexpectedValueException
- * @expectedExceptionMessage Invalid operator "~>", you probably meant to use the "~" operator
- */
- public function testParseConstraintsNudgesRubyDevsTowardsThePathOfRighteousness()
- {
- $parser = new VersionParser;
- $parser->parseConstraints('~>1.2');
- }
-
- /**
- * @dataProvider simpleConstraints
- */
- public function testParseConstraintsSimple($input, $expected)
- {
- $parser = new VersionParser;
- $this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
- }
-
- public function simpleConstraints()
- {
- return array(
- 'match any' => array('*', new EmptyConstraint()),
- 'match any/2' => array('*.*', new EmptyConstraint()),
- 'match any/3' => array('*.x.*', new EmptyConstraint()),
- 'match any/4' => array('x.X.x.*', new EmptyConstraint()),
- 'not equal' => array('<>1.0.0', new VersionConstraint('<>', '1.0.0.0')),
- 'not equal/2' => array('!=1.0.0', new VersionConstraint('!=', '1.0.0.0')),
- 'greater than' => array('>1.0.0', new VersionConstraint('>', '1.0.0.0')),
- 'lesser than' => array('<1.2.3.4', new VersionConstraint('<', '1.2.3.4-dev')),
- 'less/eq than' => array('<=1.2.3', new VersionConstraint('<=', '1.2.3.0')),
- 'great/eq than' => array('>=1.2.3', new VersionConstraint('>=', '1.2.3.0')),
- 'equals' => array('=1.2.3', new VersionConstraint('=', '1.2.3.0')),
- 'double equals' => array('==1.2.3', new VersionConstraint('=', '1.2.3.0')),
- 'no op means eq' => array('1.2.3', new VersionConstraint('=', '1.2.3.0')),
- 'completes version' => array('=1.0', new VersionConstraint('=', '1.0.0.0')),
- 'shorthand beta' => array('1.2.3b5', new VersionConstraint('=', '1.2.3.0-beta5')),
- 'accepts spaces' => array('>= 1.2.3', new VersionConstraint('>=', '1.2.3.0')),
- 'accepts spaces/2' => array('< 1.2.3', new VersionConstraint('<', '1.2.3.0-dev')),
- 'accepts spaces/3' => array('> 1.2.3', new VersionConstraint('>', '1.2.3.0')),
- 'accepts master' => array('>=dev-master', new VersionConstraint('>=', '9999999-dev')),
- 'accepts master/2' => array('dev-master', new VersionConstraint('=', '9999999-dev')),
- 'accepts arbitrary' => array('dev-feature-a', new VersionConstraint('=', 'dev-feature-a')),
- 'regression #550' => array('dev-some-fix', new VersionConstraint('=', 'dev-some-fix')),
- 'regression #935' => array('dev-CAPS', new VersionConstraint('=', 'dev-CAPS')),
- 'ignores aliases' => array('dev-master as 1.0.0', new VersionConstraint('=', '9999999-dev')),
- 'lesser than override' => array('<1.2.3.4-stable', new VersionConstraint('<', '1.2.3.4')),
- );
- }
-
- /**
- * @dataProvider wildcardConstraints
- */
- public function testParseConstraintsWildcard($input, $min, $max)
- {
- $parser = new VersionParser;
- if ($min) {
- $expected = new MultiConstraint(array($min, $max));
- } else {
- $expected = $max;
- }
-
- $this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
- }
-
- public function wildcardConstraints()
- {
- return array(
- array('2.*', new VersionConstraint('>=', '2.0.0.0-dev'), new VersionConstraint('<', '3.0.0.0-dev')),
- array('20.*', new VersionConstraint('>=', '20.0.0.0-dev'), new VersionConstraint('<', '21.0.0.0-dev')),
- array('2.0.*', new VersionConstraint('>=', '2.0.0.0-dev'), new VersionConstraint('<', '2.1.0.0-dev')),
- array('2.2.x', new VersionConstraint('>=', '2.2.0.0-dev'), new VersionConstraint('<', '2.3.0.0-dev')),
- array('2.10.X', new VersionConstraint('>=', '2.10.0.0-dev'), new VersionConstraint('<', '2.11.0.0-dev')),
- array('2.1.3.*', new VersionConstraint('>=', '2.1.3.0-dev'), new VersionConstraint('<', '2.1.4.0-dev')),
- array('0.*', null, new VersionConstraint('<', '1.0.0.0-dev')),
- );
- }
-
- /**
- * @dataProvider tildeConstraints
- */
- public function testParseTildeWildcard($input, $min, $max)
- {
- $parser = new VersionParser;
- if ($min) {
- $expected = new MultiConstraint(array($min, $max));
- } else {
- $expected = $max;
- }
-
- $this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
- }
-
- public function tildeConstraints()
- {
- return array(
- array('~1', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.0', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.0.0', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '1.1.0.0-dev')),
- array('~1.2', new VersionConstraint('>=', '1.2.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.2.3', new VersionConstraint('>=', '1.2.3.0-dev'), new VersionConstraint('<', '1.3.0.0-dev')),
- array('~1.2.3.4', new VersionConstraint('>=', '1.2.3.4-dev'), new VersionConstraint('<', '1.2.4.0-dev')),
- array('~1.2-beta',new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.2-b2', new VersionConstraint('>=', '1.2.0.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.2-BETA2', new VersionConstraint('>=', '1.2.0.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('~1.2.2-dev', new VersionConstraint('>=', '1.2.2.0-dev'), new VersionConstraint('<', '1.3.0.0-dev')),
- array('~1.2.2-stable', new VersionConstraint('>=', '1.2.2.0-stable'), new VersionConstraint('<', '1.3.0.0-dev')),
- );
- }
-
- /**
- * @dataProvider caretConstraints
- */
- public function testParseCaretWildcard($input, $min, $max)
- {
- $parser = new VersionParser;
- if ($min) {
- $expected = new MultiConstraint(array($min, $max));
- } else {
- $expected = $max;
- }
-
- $this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
- }
-
- public function caretConstraints()
- {
- return array(
- array('^1', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('^0', new VersionConstraint('>=', '0.0.0.0-dev'), new VersionConstraint('<', '1.0.0.0-dev')),
- array('^0.0', new VersionConstraint('>=', '0.0.0.0-dev'), new VersionConstraint('<', '0.1.0.0-dev')),
- array('^1.2', new VersionConstraint('>=', '1.2.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('^1.2.3-beta.2', new VersionConstraint('>=', '1.2.3.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('^1.2.3.4', new VersionConstraint('>=', '1.2.3.4-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('^1.2.3', new VersionConstraint('>=', '1.2.3.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
- array('^0.2.3', new VersionConstraint('>=', '0.2.3.0-dev'), new VersionConstraint('<', '0.3.0.0-dev')),
- array('^0.2', new VersionConstraint('>=', '0.2.0.0-dev'), new VersionConstraint('<', '0.3.0.0-dev')),
- array('^0.2.0', new VersionConstraint('>=', '0.2.0.0-dev'), new VersionConstraint('<', '0.3.0.0-dev')),
- array('^0.0.3', new VersionConstraint('>=', '0.0.3.0-dev'), new VersionConstraint('<', '0.0.4.0-dev')),
- array('^0.0.3-alpha', new VersionConstraint('>=', '0.0.3.0-alpha'), new VersionConstraint('<', '0.0.4.0-dev')),
- array('^0.0.3-dev', new VersionConstraint('>=', '0.0.3.0-dev'), new VersionConstraint('<', '0.0.4.0-dev')),
- );
- }
-
- /**
- * @dataProvider hyphenConstraints
- */
- public function testParseHyphen($input, $min, $max)
- {
- $parser = new VersionParser;
- if ($min) {
- $expected = new MultiConstraint(array($min, $max));
- } else {
- $expected = $max;
- }
-
- $this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
- }
-
- public function hyphenConstraints()
- {
- return array(
- array('1 - 2', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '3.0.0.0-dev')),
- array('1.2.3 - 2.3.4.5', new VersionConstraint('>=', '1.2.3.0-dev'), new VersionConstraint('<=', '2.3.4.5')),
- array('1.2-beta - 2.3', new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<', '2.4.0.0-dev')),
- array('1.2-beta - 2.3-dev', new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<=', '2.3.0.0-dev')),
- array('1.2-RC - 2.3.1', new VersionConstraint('>=', '1.2.0.0-RC'), new VersionConstraint('<=', '2.3.1.0')),
- array('1.2.3-alpha - 2.3-RC', new VersionConstraint('>=', '1.2.3.0-alpha'), new VersionConstraint('<=', '2.3.0.0-RC')),
- array('1 - 2.0', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.1.0.0-dev')),
- array('1 - 2.1', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.2.0.0-dev')),
- array('1.2 - 2.1.0', new VersionConstraint('>=', '1.2.0.0-dev'), new VersionConstraint('<=', '2.1.0.0')),
- array('1.3 - 2.1.3', new VersionConstraint('>=', '1.3.0.0-dev'), new VersionConstraint('<=', '2.1.3.0')),
- );
- }
-
- /**
- * @dataProvider multiConstraintProvider
- */
- public function testParseConstraintsMulti($constraint)
- {
- $parser = new VersionParser;
- $first = new VersionConstraint('>', '2.0.0.0');
- $second = new VersionConstraint('<=', '3.0.0.0');
- $multi = new MultiConstraint(array($first, $second));
- $this->assertSame((string) $multi, (string) $parser->parseConstraints($constraint));
- }
-
- public function multiConstraintProvider()
- {
- return array(
- array('>2.0,<=3.0'),
- array('>2.0 <=3.0'),
- array('>2.0 <=3.0'),
- array('>2.0, <=3.0'),
- array('>2.0 ,<=3.0'),
- array('>2.0 , <=3.0'),
- array('>2.0 , <=3.0'),
- array('> 2.0 <= 3.0'),
- array('> 2.0 , <= 3.0'),
- array(' > 2.0 , <= 3.0 '),
- );
- }
-
- public function testParseConstraintsMultiWithStabilitySuffix()
- {
- $parser = new VersionParser;
- $first = new VersionConstraint('>=', '1.1.0.0-alpha4');
- $second = new VersionConstraint('<', '1.2.9999999.9999999-dev');
- $multi = new MultiConstraint(array($first, $second));
- $this->assertSame((string) $multi, (string) $parser->parseConstraints('>=1.1.0-alpha4,<1.2.x-dev'));
-
- $first = new VersionConstraint('>=', '1.1.0.0-alpha4');
- $second = new VersionConstraint('<', '1.2.0.0-beta2');
- $multi = new MultiConstraint(array($first, $second));
- $this->assertSame((string) $multi, (string) $parser->parseConstraints('>=1.1.0-alpha4,<1.2-beta2'));
- }
-
- /**
- * @dataProvider multiConstraintProvider2
- */
- public function testParseConstraintsMultiDisjunctiveHasPrioOverConjuctive($constraint)
- {
- $parser = new VersionParser;
- $first = new VersionConstraint('>', '2.0.0.0');
- $second = new VersionConstraint('<', '2.0.5.0-dev');
- $third = new VersionConstraint('>', '2.0.6.0');
- $multi1 = new MultiConstraint(array($first, $second));
- $multi2 = new MultiConstraint(array($multi1, $third), false);
- $this->assertSame((string) $multi2, (string) $parser->parseConstraints($constraint));
- }
-
- public function multiConstraintProvider2()
- {
- return array(
- array('>2.0,<2.0.5 | >2.0.6'),
- array('>2.0,<2.0.5 || >2.0.6'),
- array('> 2.0 , <2.0.5 | > 2.0.6'),
- );
- }
-
- public function testParseConstraintsMultiWithStabilities()
- {
- $parser = new VersionParser;
- $first = new VersionConstraint('>', '2.0.0.0');
- $second = new VersionConstraint('<=', '3.0.0.0-dev');
- $multi = new MultiConstraint(array($first, $second));
- $this->assertSame((string) $multi, (string) $parser->parseConstraints('>2.0@stable,<=3.0@dev'));
- }
-
- /**
- * @dataProvider failingConstraints
- * @expectedException UnexpectedValueException
- */
- public function testParseConstraintsFails($input)
- {
- $parser = new VersionParser;
- $parser->parseConstraints($input);
- }
-
- public function failingConstraints()
- {
- return array(
- 'empty ' => array(''),
- 'invalid version' => array('1.0.0-meh'),
- 'operator abuse' => array('>2.0,,<=3.0'),
- 'operator abuse/2' => array('>2.0 ,, <=3.0'),
- 'operator abuse/3' => array('>2.0 ||| <=3.0'),
- );
- }
-
- /**
- * @dataProvider stabilityProvider
- */
- public function testParseStability($expected, $version)
- {
- $this->assertSame($expected, VersionParser::parseStability($version));
- }
-
- public function stabilityProvider()
- {
- return array(
- array('stable', '1'),
- array('stable', '1.0'),
- array('stable', '3.2.1'),
- array('stable', 'v3.2.1'),
- array('dev', 'v2.0.x-dev'),
- array('dev', 'v2.0.x-dev#abc123'),
- array('dev', 'v2.0.x-dev#trunk/@123'),
- array('RC', '3.0-RC2'),
- array('dev', 'dev-master'),
- array('dev', '3.1.2-dev'),
- array('stable', '3.1.2-pl2'),
- array('stable', '3.1.2-patch'),
- array('alpha', '3.1.2-alpha5'),
- array('beta', '3.1.2-beta'),
- array('beta', '2.0B1'),
- array('alpha', '1.2.0a1'),
- array('alpha', '1.2_a1'),
- array('RC', '2.0.0rc1')
- );
- }
-
- public function pluginApiVersions()
- {
- return array(
- array('1.0'),
- array('1.0.0'),
- array('1.0.0.0'),
- array('1'),
- array('=1.0.0'),
- array('==1.0'),
- array('~1.0.0'),
- array('*'),
- array('3.0.*'),
- array('@stable'),
- array('1.0.0@stable'),
- array('^5.1'),
- array('>=1.0.0 <2.5'),
- array('x'),
- array('1.0.0-dev'),
- );
- }
-
- /**
- * @dataProvider pluginApiVersions
- */
- public function testPluginApiVersionAreKeptAsDeclared($apiVersion)
- {
- $parser = new VersionParser;
-
- /** @var Link[] $links */
- $links = $parser->parseLinks('Plugin', '9.9.9', '', array('composer-plugin-api' => $apiVersion));
-
- $this->assertArrayHasKey('composer-plugin-api', $links);
- $this->assertSame($apiVersion, $links['composer-plugin-api']->getConstraint()->getPrettyString());
- }
-
- public function testPluginApiVersionDoesSupportSelfVersion()
- {
- $parser = new VersionParser;
-
- /** @var Link[] $links */
- $links = $parser->parseLinks('Plugin', '6.6.6', '', array('composer-plugin-api' => 'self.version'));
-
- $this->assertArrayHasKey('composer-plugin-api', $links);
- $this->assertSame('6.6.6', $links['composer-plugin-api']->getConstraint()->getPrettyString());
- }
-}
diff --git a/tests/Composer/Test/Package/Version/VersionSelectorTest.php b/tests/Composer/Test/Package/Version/VersionSelectorTest.php
index 6547e7056..a48cc805d 100644
--- a/tests/Composer/Test/Package/Version/VersionSelectorTest.php
+++ b/tests/Composer/Test/Package/Version/VersionSelectorTest.php
@@ -13,7 +13,7 @@
namespace Composer\Test\Package\Version;
use Composer\Package\Version\VersionSelector;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
class VersionSelectorTest extends \PHPUnit_Framework_TestCase
{
diff --git a/tests/Composer/Test/Plugin/PluginInstallerTest.php b/tests/Composer/Test/Plugin/PluginInstallerTest.php
index cd05b922f..b449d7e90 100644
--- a/tests/Composer/Test/Plugin/PluginInstallerTest.php
+++ b/tests/Composer/Test/Plugin/PluginInstallerTest.php
@@ -216,7 +216,7 @@ class PluginInstallerTest extends TestCase
}
/**
- * @param string $newPluginApiVersion
+ * @param string $newPluginApiVersion
* @param CompletePackage[] $plugins
*/
private function setPluginApiVersionWithPlugins($newPluginApiVersion, array $plugins = array())
@@ -242,7 +242,7 @@ class PluginInstallerTest extends TestCase
$this->repository
->expects($this->any())
->method('getPackages')
- ->will($this->returnCallback(function() use($plugApiInternalPackage, $plugins) {
+ ->will($this->returnCallback(function () use ($plugApiInternalPackage, $plugins) {
return array_merge(array($plugApiInternalPackage), $plugins);
}));
diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php
index 5109ee41f..3b35714df 100644
--- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php
+++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php
@@ -12,12 +12,11 @@
namespace Composer\Test\Repository;
-use Composer\Repository\ComposerRepository;
use Composer\IO\NullIO;
use Composer\Test\Mock\FactoryMock;
use Composer\TestCase;
use Composer\Package\Loader\ArrayLoader;
-use Composer\Package\Version\VersionParser;
+use Composer\Semver\VersionParser;
class ComposerRepositoryTest extends TestCase
{
@@ -76,8 +75,8 @@ class ComposerRepositoryTest extends TestCase
array('foo/bar' => array(
'name' => 'foo/bar',
'versions' => array(
- '1.0.0' => array('name' => 'foo/bar', 'version' => '1.0.0')
- )
+ '1.0.0' => array('name' => 'foo/bar', 'version' => '1.0.0'),
+ ),
)),
),
// New repository format
@@ -111,7 +110,7 @@ class ComposerRepositoryTest extends TestCase
$properties = array(
'cache' => $cache,
'loader' => new ArrayLoader(),
- 'providerListing' => array('p/a.json' => array('sha256' => 'xxx'))
+ 'providerListing' => array('p/a.json' => array('sha256' => 'xxx')),
);
foreach ($properties as $property => $value) {
@@ -141,7 +140,7 @@ class ComposerRepositoryTest extends TestCase
'name' => 'a',
'version' => '0.6',
)),
- )
+ ),
)));
$pool = $this->getMock('Composer\DependencyResolver\Pool');
diff --git a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php
index fa1ec6d5b..6f8b71d20 100644
--- a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php
+++ b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php
@@ -26,7 +26,7 @@ class FilesystemRepositoryTest extends TestCase
->expects($this->once())
->method('read')
->will($this->returnValue(array(
- array('name' => 'package1', 'version' => '1.0.0-beta', 'type' => 'vendor')
+ array('name' => 'package1', 'version' => '1.0.0-beta', 'type' => 'vendor'),
)));
$json
->expects($this->once())
@@ -94,7 +94,7 @@ class FilesystemRepositoryTest extends TestCase
->expects($this->once())
->method('write')
->with(array(
- array('name' => 'mypkg', 'type' => 'library', 'version' => '0.1.10', 'version_normalized' => '0.1.10.0')
+ array('name' => 'mypkg', 'type' => 'library', 'version' => '0.1.10', 'version_normalized' => '0.1.10.0'),
));
$repository->addPackage($this->getPackage('mypkg', '0.1.10'));
diff --git a/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json
new file mode 100644
index 000000000..985b89947
--- /dev/null
+++ b/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json
@@ -0,0 +1,4 @@
+{
+ "name": "test/path-versioned",
+ "version": "0.0.2"
+}
\ No newline at end of file
diff --git a/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json
new file mode 100644
index 000000000..cddefceb2
--- /dev/null
+++ b/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json
@@ -0,0 +1,3 @@
+{
+ "name": "test/path-unversioned"
+}
\ No newline at end of file
diff --git a/tests/Composer/Test/Repository/PathRepositoryTest.php b/tests/Composer/Test/Repository/PathRepositoryTest.php
new file mode 100644
index 000000000..47b7ac24f
--- /dev/null
+++ b/tests/Composer/Test/Repository/PathRepositoryTest.php
@@ -0,0 +1,106 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+use Composer\Package\Loader\ArrayLoader;
+use Composer\Semver\VersionParser;
+use Composer\TestCase;
+
+class PathRepositoryTest extends TestCase
+{
+ public function testLoadPackageFromFileSystemWithVersion()
+ {
+ $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
+ ->getMock();
+
+ $config = new \Composer\Config();
+ $loader = new ArrayLoader(new VersionParser());
+ $versionGuesser = null;
+
+ $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-version'));
+ $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config, $loader);
+ $repository->getPackages();
+
+ $this->assertEquals(1, $repository->count());
+ $this->assertTrue($repository->hasPackage($this->getPackage('test/path-versioned', '0.0.2')));
+ }
+
+ public function testLoadPackageFromFileSystemWithoutVersion()
+ {
+ $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
+ ->getMock();
+
+ $config = new \Composer\Config();
+ $loader = new ArrayLoader(new VersionParser());
+ $versionGuesser = null;
+
+ $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'without-version'));
+ $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config, $loader);
+ $packages = $repository->getPackages();
+
+ $this->assertEquals(1, $repository->count());
+
+ $package = $packages[0];
+ $this->assertEquals('test/path-unversioned', $package->getName());
+
+ $packageVersion = $package->getVersion();
+ $this->assertTrue(!empty($packageVersion));
+ }
+
+ public function testLoadPackageFromFileSystemWithWildcard()
+ {
+ $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
+ ->getMock();
+
+ $config = new \Composer\Config();
+ $loader = new ArrayLoader(new VersionParser());
+ $versionGuesser = null;
+
+ $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
+ $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config, $loader);
+ $packages = $repository->getPackages();
+
+ $this->assertEquals(2, $repository->count());
+
+ $package = $packages[0];
+ $this->assertEquals('test/path-versioned', $package->getName());
+
+ $package = $packages[1];
+ $this->assertEquals('test/path-unversioned', $package->getName());
+ }
+
+ /**
+ * Verify relative repository URLs remain relative, see #4439
+ */
+ public function testUrlRemainsRelative()
+ {
+ $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
+ ->getMock();
+
+ $config = new \Composer\Config();
+ $loader = new ArrayLoader(new VersionParser());
+ $versionGuesser = null;
+
+ $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-version'));
+ $relativeUrl = ltrim(substr($repositoryUrl, strlen(getcwd())), DIRECTORY_SEPARATOR);
+
+ $repository = new PathRepository(array('url' => $relativeUrl), $ioInterface, $config, $loader);
+ $packages = $repository->getPackages();
+
+ $this->assertEquals(1, $repository->count());
+
+ $package = $packages[0];
+ $this->assertEquals('test/path-versioned', $package->getName());
+ $this->assertEquals(rtrim($relativeUrl, DIRECTORY_SEPARATOR), rtrim($package->getDistUrl(), DIRECTORY_SEPARATOR));
+ }
+}
diff --git a/tests/Composer/Test/Repository/Pear/ChannelReaderTest.php b/tests/Composer/Test/Repository/Pear/ChannelReaderTest.php
index c22250a04..3e68282f4 100644
--- a/tests/Composer/Test/Repository/Pear/ChannelReaderTest.php
+++ b/tests/Composer/Test/Repository/Pear/ChannelReaderTest.php
@@ -13,8 +13,8 @@
namespace Composer\Repository\Pear;
use Composer\TestCase;
-use Composer\Package\Version\VersionParser;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\Constraint;
use Composer\Package\Link;
use Composer\Package\CompletePackage;
use Composer\Test\Mock\RemoteFilesystemMock;
@@ -106,18 +106,18 @@ class ChannelReaderTest extends TestCase
'ext',
'xml'
),
- )
+ ),
)
)
- )
+ ),
)
- )
+ ),
)
);
$packages = $ref->invoke($reader, $channelInfo, new VersionParser());
- $expectedPackage = new CompletePackage('pear-test.loc/sample', '1.0.0.1' , '1.0.0.1');
+ $expectedPackage = new CompletePackage('pear-test.loc/sample', '1.0.0.1', '1.0.0.1');
$expectedPackage->setType('pear-library');
$expectedPackage->setDistType('file');
$expectedPackage->setDescription('description');
@@ -135,7 +135,7 @@ class ChannelReaderTest extends TestCase
'*-ext-xml' => '*',
));
$expectedPackage->setReplaces(array(
- new Link('pear-test.loc/sample', 'pear-test/sample', new VersionConstraint('==', '1.0.0.1'), 'replaces', '== 1.0.0.1'),
+ new Link('pear-test.loc/sample', 'pear-test/sample', new Constraint('==', '1.0.0.1'), 'replaces', '== 1.0.0.1'),
));
$this->assertCount(1, $packages);
@@ -144,7 +144,7 @@ class ChannelReaderTest extends TestCase
private function createConstraint($operator, $version)
{
- $constraint = new VersionConstraint($operator, $version);
+ $constraint = new Constraint($operator, $version);
$constraint->setPrettyString($operator.' '.$version);
return $constraint;
diff --git a/tests/Composer/Test/Repository/PearRepositoryTest.php b/tests/Composer/Test/Repository/PearRepositoryTest.php
index 7eaad13e7..f076d72cc 100644
--- a/tests/Composer/Test/Repository/PearRepositoryTest.php
+++ b/tests/Composer/Test/Repository/PearRepositoryTest.php
@@ -40,7 +40,7 @@ class PearRepositoryTest extends TestCase
);
$repoConfig = array(
- 'url' => $url
+ 'url' => $url,
);
$this->createRepository($repoConfig);
@@ -64,7 +64,7 @@ class PearRepositoryTest extends TestCase
public function testRepositoryRead($url, array $expectedPackages)
{
$repoConfig = array(
- 'url' => $url
+ 'url' => $url,
);
if (!@file_get_contents('http://'.$url)) {
@@ -88,37 +88,37 @@ class PearRepositoryTest extends TestCase
'pear.php.net',
array(
array('name' => 'pear-pear.php.net/PEAR', 'version' => '1.9.4'),
- )
+ ),
),
array(
'pear.pdepend.org',
array(
array('name' => 'pear-pear.pdepend.org/PHP_Depend', 'version' => '1.0.5'),
- )
+ ),
),
array(
'pear.phpmd.org',
array(
array('name' => 'pear-pear.phpmd.org/PHP_PMD', 'version' => '1.3.3'),
- )
+ ),
),
array(
'pear.doctrine-project.org',
array(
array('name' => 'pear-pear.doctrine-project.org/DoctrineORM', 'version' => '2.2.2'),
- )
+ ),
),
array(
'pear.symfony-project.com',
array(
array('name' => 'pear-pear.symfony-project.com/YAML', 'version' => '1.0.6'),
- )
+ ),
),
array(
'pear.pirum-project.org',
array(
array('name' => 'pear-pear.pirum-project.org/Pirum', 'version' => '1.1.4'),
- )
+ ),
),
);
}
diff --git a/tests/Composer/Test/Util/GitHubTest.php b/tests/Composer/Test/Util/GitHubTest.php
index 1363afd15..83d18dbe4 100644
--- a/tests/Composer/Test/Util/GitHubTest.php
+++ b/tests/Composer/Test/Util/GitHubTest.php
@@ -18,8 +18,8 @@ use RecursiveArrayIterator;
use RecursiveIteratorIterator;
/**
-* @author Rob Bast
-*/
+ * @author Rob Bast
+ */
class GitHubTest extends \PHPUnit_Framework_TestCase
{
private $username = 'username';
diff --git a/tests/Composer/Test/Util/PerforceTest.php b/tests/Composer/Test/Util/PerforceTest.php
index dc727096d..f4d12d1be 100644
--- a/tests/Composer/Test/Util/PerforceTest.php
+++ b/tests/Composer/Test/Util/PerforceTest.php
@@ -53,7 +53,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'depot' => self::TEST_DEPOT,
'branch' => self::TEST_BRANCH,
'p4user' => self::TEST_P4USER,
- 'unique_perforce_client_name' => self::TEST_CLIENT_NAME
+ 'unique_perforce_client_name' => self::TEST_CLIENT_NAME,
);
}
@@ -222,9 +222,9 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'depot' => 'depot',
'branch' => 'branch',
'p4user' => 'user',
- 'p4password' => 'TEST_PASSWORD'
+ 'p4password' => 'TEST_PASSWORD',
);
- $this->perforce = new Perforce($repoConfig, 'port', 'path', $this->processExecutor, false, $this->getMockIOInterface(), 'TEST');
+ $this->perforce = new Perforce($repoConfig, 'port', 'path', $this->processExecutor, false, $this->getMockIOInterface(), 'TEST');
$password = $this->perforce->queryP4Password();
$this->assertEquals('TEST_PASSWORD', $password);
}
@@ -476,7 +476,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
- 'autoload' => array('psr-0' => array())
+ 'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
@@ -517,7 +517,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
- 'autoload' => array('psr-0' => array())
+ 'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
@@ -546,7 +546,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
- 'autoload' => array('psr-0' => array())
+ 'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
@@ -588,7 +588,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
- 'autoload' => array('psr-0' => array())
+ 'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
@@ -662,7 +662,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'"psr-0" : {',
'}',
'}',
- '}'
+ '}',
);
return implode($composer_json);
@@ -688,7 +688,7 @@ class PerforceTest extends \PHPUnit_Framework_TestCase
'SubmitOptions: revertunchanged',
PHP_EOL,
'LineEnd: local',
- PHP_EOL
+ PHP_EOL,
);
if ($withStream) {
$expectedArray[] = 'Stream:';
diff --git a/tests/Composer/Test/Util/RemoteFilesystemTest.php b/tests/Composer/Test/Util/RemoteFilesystemTest.php
index 04502ebdc..d09993130 100644
--- a/tests/Composer/Test/Util/RemoteFilesystemTest.php
+++ b/tests/Composer/Test/Util/RemoteFilesystemTest.php
@@ -13,7 +13,6 @@
namespace Composer\Test\Util;
use Composer\Util\RemoteFilesystem;
-use Installer\Exception;
class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
{
@@ -137,6 +136,9 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
$this->assertNull($this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, 'HTTP/1.1 404 Not Found', 404, 0, 0));
}
+ /**
+ * @group slow
+ */
public function testCaptureAuthenticationParamsFromUrl()
{
$io = $this->getMock('Composer\IO\IOInterface');
diff --git a/tests/Composer/Test/Util/SpdxLicenseTest.php b/tests/Composer/Test/Util/SpdxLicenseTest.php
deleted file mode 100644
index d4665954e..000000000
--- a/tests/Composer/Test/Util/SpdxLicenseTest.php
+++ /dev/null
@@ -1,132 +0,0 @@
-license = new SpdxLicense;
- }
-
- public static function provideValidLicenses()
- {
- $json = file_get_contents(__DIR__ . '/../../../../res/spdx-licenses.json');
-
- $licenses = json_decode($json, true);
-
- $identifiers = array_keys($licenses);
-
- $valid = array_merge(
- array(
- "MIT",
- "NONE",
- "NOASSERTION",
- "LicenseRef-3",
- array("LGPL-2.0", "GPL-3.0+"),
- "(LGPL-2.0 or GPL-3.0+)",
- "(EUDatagrid and GPL-3.0+)",
- ),
- $identifiers
- );
-
- foreach ($valid as &$r) {
- $r = array($r);
- }
-
- return $valid;
- }
-
- public static function provideInvalidLicenses()
- {
- return array(
- array(""),
- array(array()),
- array("The system pwns you"),
- array("()"),
- array("(MIT)"),
- array("MIT NONE"),
- array("MIT (MIT and MIT)"),
- array("(MIT and MIT) MIT"),
- array(array("LGPL-2.0", "The system pwns you")),
- array("and GPL-3.0+"),
- array("EUDatagrid and GPL-3.0+"),
- array("(GPL-3.0 and GPL-2.0 or GPL-3.0+)"),
- array("(EUDatagrid and GPL-3.0+ and )"),
- array("(EUDatagrid xor GPL-3.0+)"),
- array("(MIT Or MIT)"),
- array("(NONE or MIT)"),
- array("(NOASSERTION or MIT)"),
- );
- }
-
- public static function provideInvalidArgument()
- {
- return array(
- array(null),
- array(new \stdClass),
- array(array(new \stdClass)),
- array(array("mixed", new \stdClass)),
- array(array(new \stdClass, new \stdClass)),
- );
- }
-
- /**
- * @dataProvider provideValidLicenses
- * @param $license
- */
- public function testValidate($license)
- {
- $this->assertTrue($this->license->validate($license));
- }
-
- /**
- * @dataProvider provideInvalidLicenses
- * @param string|array $invalidLicense
- */
- public function testInvalidLicenses($invalidLicense)
- {
- $this->assertFalse($this->license->validate($invalidLicense));
- }
-
- /**
- * @dataProvider provideInvalidArgument
- * @expectedException InvalidArgumentException
- */
- public function testInvalidArgument($invalidArgument)
- {
- $this->license->validate($invalidArgument);
- }
-
- public function testGetLicenseByIdentifier()
- {
- $license = $this->license->getLicenseByIdentifier('AGPL-1.0');
- $this->assertEquals($license[0], 'Affero General Public License v1.0'); // fullname
- $this->assertFalse($license[1]); // osi approved
- }
-
- public function testGetIdentifierByName()
- {
- $identifier = $this->license->getIdentifierByName('Affero General Public License v1.0');
- $this->assertEquals($identifier, 'AGPL-1.0');
-
- $identifier = $this->license->getIdentifierByName('BSD 2-clause "Simplified" License');
- $this->assertEquals($identifier, 'BSD-2-Clause');
- }
-
- public function testIsOsiApprovedByIdentifier()
- {
- $osiApproved = $this->license->isOsiApprovedByIdentifier('MIT');
- $this->assertTrue($osiApproved);
-
- $osiApproved = $this->license->isOsiApprovedByIdentifier('AGPL-1.0');
- $this->assertFalse($osiApproved);
- }
-}
diff --git a/tests/Composer/Test/Util/StreamContextFactoryTest.php b/tests/Composer/Test/Util/StreamContextFactoryTest.php
index 2cc419670..590a868fd 100644
--- a/tests/Composer/Test/Util/StreamContextFactoryTest.php
+++ b/tests/Composer/Test/Util/StreamContextFactoryTest.php
@@ -52,11 +52,11 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
return array(
array(
$a = array('http' => array('follow_location' => 1, 'max_redirects' => 20)), array(),
- array('options' => $a), array()
+ array('options' => $a), array(),
),
array(
$a = array('http' => array('method' => 'GET', 'max_redirects' => 20, 'follow_location' => 1)), array('http' => array('method' => 'GET')),
- array('options' => $a, 'notification' => $f = function () {}), array('notification' => $f)
+ array('options' => $a, 'notification' => $f = function () {}), array('notification' => $f),
),
);
}
@@ -143,8 +143,8 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
'follow_location' => 1,
), 'ssl' => array(
'SNI_enabled' => true,
- 'SNI_server_name' => 'example.org'
- )
+ 'SNI_server_name' => 'example.org',
+ ),
);
if (PHP_VERSION_ID >= 50600) {
unset($expected['ssl']['SNI_server_name']);
@@ -173,8 +173,8 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
'follow_location' => 1,
), 'ssl' => array(
'SNI_enabled' => true,
- 'SNI_server_name' => 'example.org'
- )
+ 'SNI_server_name' => 'example.org',
+ ),
);
if (PHP_VERSION_ID >= 50600) {
unset($expected['ssl']['SNI_server_name']);
@@ -221,17 +221,17 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
{
$options = array(
'http' => array(
- 'header' => "X-Foo: bar\r\nContent-Type: application/json\r\nAuthorization: Basic aW52YWxpZA=="
- )
+ 'header' => "X-Foo: bar\r\nContent-Type: application/json\r\nAuthorization: Basic aW52YWxpZA==",
+ ),
);
$expectedOptions = array(
'http' => array(
'header' => array(
"X-Foo: bar",
"Authorization: Basic aW52YWxpZA==",
- "Content-Type: application/json"
- )
- )
+ "Content-Type: application/json",
+ ),
+ ),
);
$context = StreamContextFactory::getContext('http://example.org', $options);
$ctxoptions = stream_context_get_options($context);
diff --git a/tests/Composer/Test/Util/SvnTest.php b/tests/Composer/Test/Util/SvnTest.php
index b1f19ca1a..c54c9c504 100644
--- a/tests/Composer/Test/Util/SvnTest.php
+++ b/tests/Composer/Test/Util/SvnTest.php
@@ -60,9 +60,9 @@ class SvnTest extends \PHPUnit_Framework_TestCase
$config->merge(array(
'config' => array(
'http-basic' => array(
- 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar')
- )
- )
+ 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar'),
+ ),
+ ),
));
$svn = new Svn($url, new NullIO, $config);
@@ -81,9 +81,9 @@ class SvnTest extends \PHPUnit_Framework_TestCase
array(
'config' => array(
'http-basic' => array(
- 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar')
- )
- )
+ 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar'),
+ ),
+ ),
)
);
@@ -104,9 +104,9 @@ class SvnTest extends \PHPUnit_Framework_TestCase
array(
'config' => array(
'http-basic' => array(
- 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar')
- )
- )
+ 'svn.apache.org' => array('username' => 'foo', 'password' => 'bar'),
+ ),
+ ),
)
);
diff --git a/tests/Composer/TestCase.php b/tests/Composer/TestCase.php
index 760b57291..2057c09b8 100644
--- a/tests/Composer/TestCase.php
+++ b/tests/Composer/TestCase.php
@@ -12,10 +12,9 @@
namespace Composer;
-use Composer\Package\Version\VersionParser;
-use Composer\Package\Package;
+use Composer\Semver\VersionParser;
use Composer\Package\AliasPackage;
-use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Semver\Constraint\Constraint;
use Composer\Util\Filesystem;
abstract class TestCase extends \PHPUnit_Framework_TestCase
@@ -33,7 +32,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
protected function getVersionConstraint($operator, $version)
{
- $constraint = new VersionConstraint(
+ $constraint = new Constraint(
$operator,
self::getVersionParser()->normalize($version)
);