Merge branch 'master' of https://github.com/composer/composer
Conflicts: src/Composer/Factory.phppull/1407/head
commit
ad9c3d3b30
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,3 +1,33 @@
|
|||
### 1.0.0-alpha9 (2014-12-07)
|
||||
|
||||
* Added `remove` command to do the reverse of `require`
|
||||
* Added --ignore-platform-reqs to `install`/`update` commands to install even if you are missing a php extension or have an invalid php version
|
||||
* Added a warning when abandoned packages are being installed
|
||||
* Added auto-selection of the version constraint in the `require` command, which can now be used simply as `composer require foo/bar`
|
||||
* Added ability to define custom composer commands using scripts
|
||||
* Added `browse` command to open a browser to the given package's repo URL (or homepage with `-H`)
|
||||
* Added an `autoload-dev` section to declare dev-only autoload rules + a --no-dev flag to dump-autoload
|
||||
* Added an `auth.json` file, with `store-auths` config option
|
||||
* Added a `http-basic` config option to store login/pwds to hosts
|
||||
* Added failover to source/dist and vice-versa in case a download method fails
|
||||
* Added --path (-P) flag to the show command to see the install path of packages
|
||||
* Added --update-with-dependencies and --update-no-dev flags to the require command
|
||||
* Added `optimize-autoloader` config option to force the `-o` flag from the config
|
||||
* Added `clear-cache` command
|
||||
* Added a GzipDownloader to download single gzipped files
|
||||
* Added `ssh` support in the `github-protocols` config option
|
||||
* Added `pre-dependencies-solving` and `post-dependencies-solving` events
|
||||
* Added `pre-archive-cmd` and `post-archive-cmd` script events to the `archive` command
|
||||
* Added a `no-api` flag to GitHub VCS repos to skip the API but still get zip downloads
|
||||
* Added http-basic auth support for private git repos not on github
|
||||
* Added support for autoloading `.hh` files when running HHVM
|
||||
* Added support for PHP 5.6
|
||||
* Added support for OTP auth when retrieving a GitHub API key
|
||||
* Fixed isolation of `files` autoloaded scripts to ensure they can not affect anything
|
||||
* Improved performance of solving dependencies
|
||||
* Improved SVN and Perforce support
|
||||
* A boatload of minor fixes, documentation additions and UX improvements
|
||||
|
||||
### 1.0.0-alpha8 (2014-01-06)
|
||||
|
||||
* Break: The `install` command now has --dev enabled by default. --no-dev can be used to install without dev requirements
|
||||
|
|
|
@ -120,17 +120,17 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.6.0",
|
||||
"version": "v2.6.1",
|
||||
"target-dir": "Symfony/Component/Console",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Console.git",
|
||||
"reference": "d3bac228fd7a2aac9193e241b239880b3ba39a10"
|
||||
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Console/zipball/d3bac228fd7a2aac9193e241b239880b3ba39a10",
|
||||
"reference": "d3bac228fd7a2aac9193e241b239880b3ba39a10",
|
||||
"url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8",
|
||||
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -173,21 +173,21 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-11-20 13:24:23"
|
||||
"time": "2014-12-02 20:19:20"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.6.0",
|
||||
"version": "v2.6.1",
|
||||
"target-dir": "Symfony/Component/Finder",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Finder.git",
|
||||
"reference": "d574347c652a14cfee0349f744c7880e1d9029fd"
|
||||
"reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Finder/zipball/d574347c652a14cfee0349f744c7880e1d9029fd",
|
||||
"reference": "d574347c652a14cfee0349f744c7880e1d9029fd",
|
||||
"url": "https://api.github.com/repos/symfony/Finder/zipball/0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721",
|
||||
"reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -220,21 +220,21 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-11-28 10:00:40"
|
||||
"time": "2014-12-02 20:19:20"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.6.0",
|
||||
"version": "v2.6.1",
|
||||
"target-dir": "Symfony/Component/Process",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Process.git",
|
||||
"reference": "dc88f75d1c07791e5733f90be747961dce26cf05"
|
||||
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Process/zipball/dc88f75d1c07791e5733f90be747961dce26cf05",
|
||||
"reference": "dc88f75d1c07791e5733f90be747961dce26cf05",
|
||||
"url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
|
||||
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -267,7 +267,7 @@
|
|||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-11-04 14:29:39"
|
||||
"time": "2014-12-02 20:19:20"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -327,16 +327,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.0.12",
|
||||
"version": "2.0.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "7ce9da20f96964bb7a4033f53834df13328dbeab"
|
||||
"reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7ce9da20f96964bb7a4033f53834df13328dbeab",
|
||||
"reference": "7ce9da20f96964bb7a4033f53834df13328dbeab",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5",
|
||||
"reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -388,7 +388,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2014-12-02 13:17:01"
|
||||
"time": "2014-12-03 06:41:44"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -574,16 +574,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.3.5",
|
||||
"version": "4.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "2dab9d593997db4abcf58d0daf798eb4e9cecfe1"
|
||||
"reference": "bbe7bcb83b6ec1a9eaabbe1b70d4795027c53ee0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2dab9d593997db4abcf58d0daf798eb4e9cecfe1",
|
||||
"reference": "2dab9d593997db4abcf58d0daf798eb4e9cecfe1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bbe7bcb83b6ec1a9eaabbe1b70d4795027c53ee0",
|
||||
"reference": "bbe7bcb83b6ec1a9eaabbe1b70d4795027c53ee0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -600,8 +600,9 @@
|
|||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.0",
|
||||
"sebastian/diff": "~1.1",
|
||||
"sebastian/environment": "~1.0",
|
||||
"sebastian/environment": "~1.1",
|
||||
"sebastian/exporter": "~1.0",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
|
@ -614,7 +615,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.3.x-dev"
|
||||
"dev-master": "4.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -623,10 +624,6 @@
|
|||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
"",
|
||||
"../../symfony/yaml/"
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
|
@ -638,13 +635,13 @@
|
|||
}
|
||||
],
|
||||
"description": "The PHP Unit Testing framework.",
|
||||
"homepage": "http://www.phpunit.de/",
|
||||
"homepage": "https://phpunit.de/",
|
||||
"keywords": [
|
||||
"phpunit",
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2014-11-11 10:11:09"
|
||||
"time": "2014-12-05 06:49:03"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
|
@ -703,16 +700,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef"
|
||||
"reference": "c484a80f97573ab934e37826dba0135a3301b26a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
|
||||
"reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a",
|
||||
"reference": "c484a80f97573ab934e37826dba0135a3301b26a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -726,7 +723,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -763,7 +760,7 @@
|
|||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2014-05-11 23:00:21"
|
||||
"time": "2014-11-16 21:32:38"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
|
@ -932,6 +929,57 @@
|
|||
],
|
||||
"time": "2014-09-10 00:51:36"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
|
||||
"reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-uopz": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Snapshotting of global state",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"time": "2014-10-06 09:23:50"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.3",
|
||||
|
@ -969,17 +1017,17 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.6.0",
|
||||
"version": "v2.6.1",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "51c845cf3e4bfc182d1d5c05ed1c7338361d86f8"
|
||||
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/51c845cf3e4bfc182d1d5c05ed1c7338361d86f8",
|
||||
"reference": "51c845cf3e4bfc182d1d5c05ed1c7338361d86f8",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20",
|
||||
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1012,7 +1060,7 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-11-20 13:24:23"
|
||||
"time": "2014-12-02 20:19:20"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -47,7 +47,7 @@ any version beginning with `1.2`.
|
|||
## System Requirements
|
||||
|
||||
Composer requires PHP 5.3.2+ to run. A few sensitive php settings and compile
|
||||
flags are also required, but the installer will warn you about any
|
||||
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
|
||||
|
@ -56,14 +56,17 @@ git, svn or hg depending on how the package is version-controlled.
|
|||
Composer is multi-platform and we strive to make it run equally well on Windows,
|
||||
Linux and OSX.
|
||||
|
||||
## Installation - *nix
|
||||
## Installation - Linux / Unix / OSX
|
||||
|
||||
### Downloading the Composer Executable
|
||||
|
||||
There are in short, two ways to install Composer. Locally as part of your
|
||||
project, or globally as a system wide executable.
|
||||
|
||||
#### Locally
|
||||
|
||||
To actually get Composer, we need to do two things. The first one is installing
|
||||
Composer (again, this means downloading it into your project):
|
||||
Installing Composer locally is a matter of just running the installer in your
|
||||
project directory:
|
||||
|
||||
```sh
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
@ -76,8 +79,8 @@ curl -sS https://getcomposer.org/installer | php
|
|||
php -r "readfile('https://getcomposer.org/installer');" | php
|
||||
```
|
||||
|
||||
This 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
|
||||
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.
|
||||
|
||||
|
@ -106,17 +109,6 @@ mv composer.phar /usr/local/bin/composer
|
|||
|
||||
Then, just run `composer` in order to run Composer instead of `php composer.phar`.
|
||||
|
||||
#### Globally (on OSX via homebrew)
|
||||
|
||||
Composer is part of the homebrew-php project.
|
||||
|
||||
```sh
|
||||
brew update
|
||||
brew tap homebrew/dupes
|
||||
brew tap homebrew/php
|
||||
brew install composer
|
||||
```
|
||||
|
||||
## Installation - Windows
|
||||
|
||||
### Using the Installer
|
||||
|
@ -127,6 +119,9 @@ 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.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
Change to a directory on your `PATH` and run the install snippet to download
|
||||
|
|
|
@ -1,29 +1,8 @@
|
|||
# Basic usage
|
||||
|
||||
## Installation
|
||||
## Installing
|
||||
|
||||
To install Composer, you just need to download the `composer.phar` executable.
|
||||
|
||||
```sh
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
```
|
||||
|
||||
For the details, see the [Introduction](00-intro.md) chapter.
|
||||
|
||||
To check if Composer is working, just run the PHAR through `php`:
|
||||
|
||||
```sh
|
||||
php composer.phar
|
||||
```
|
||||
|
||||
This should give you a list of available commands.
|
||||
|
||||
> **Note:** You can also perform the checks only without downloading Composer
|
||||
> by using the `--check` option. For more information, just use `--help`.
|
||||
>
|
||||
> ```sh
|
||||
> curl -sS https://getcomposer.org/installer | php -- --help
|
||||
> ```
|
||||
If you have not yet installed Composer, refer to to the [Intro](00-intro.md) chapter.
|
||||
|
||||
## `composer.json`: Project Setup
|
||||
|
||||
|
@ -73,16 +52,18 @@ means any version in the `1.0` development branch. It would match `1.0.0`,
|
|||
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` <code>>=1.0,<1.1 | >=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a comma (`,`) will be treated as a **logical AND**. A pipe (<code>|</code>) will be treated as a **logical OR**. AND has higher precedence than OR.
|
||||
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.
|
||||
Range | `>=1.0` `>=1.0 <2.0` <code>>=1.0 <1.1 || >=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a space (<code> </code>) or comma (`,`) will be treated as a **logical AND**. A double pipe (<code>||</code>) 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 Operator)
|
||||
### Next Significant Release (Tilde and Caret Operators)
|
||||
|
||||
The `~` operator is best explained by example: `~1.2` is equivalent to
|
||||
`>=1.2,<2.0`, while `~1.2.3` is equivalent to `>=1.2.3,<1.3`. As you can see
|
||||
`>=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
|
||||
|
@ -90,6 +71,12 @@ 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.
|
||||
|
|
|
@ -140,7 +140,9 @@ php composer.phar update vendor/*
|
|||
* **--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.
|
||||
So all packages with their dependencies are updated recursively.
|
||||
* **--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`.
|
||||
|
||||
## require
|
||||
|
||||
|
@ -482,11 +484,20 @@ performance.
|
|||
a bit of time to run so it is currently not done by default.
|
||||
* **--no-dev:** Disables autoload-dev rules.
|
||||
|
||||
## clear-cache
|
||||
|
||||
Deletes all content from Composer's cache directories.
|
||||
|
||||
## licenses
|
||||
|
||||
Lists the name, version and license of every package installed. Use
|
||||
`--format=json` to get machine readable output.
|
||||
|
||||
### Options
|
||||
|
||||
* **--no-dev:** Remove dev dependencies from the output
|
||||
* **--format:** Format of the output: text or json (default: "text")
|
||||
|
||||
## run-script
|
||||
|
||||
To run [scripts](articles/scripts.md) manually you can use this command,
|
||||
|
|
|
@ -345,10 +345,10 @@ dependencies from being installed.
|
|||
Lists packages that conflict with this version of this package. They
|
||||
will not be allowed to be installed together with your package.
|
||||
|
||||
Note that when specifying ranges like `<1.0, >= 1.1` in a `conflict` link,
|
||||
Note that when specifying ranges like `<1.0 >=1.1` in a `conflict` link,
|
||||
this will state a conflict with all versions that are less than 1.0 *and* equal
|
||||
or newer than 1.1 at the same time, which is probably not what you want. You
|
||||
probably want to go for `<1.0 | >= 1.1` in this case.
|
||||
probably want to go for `<1.0 | >=1.1` in this case.
|
||||
|
||||
#### replace
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<!--
|
||||
tagline: Access privately hosted packages
|
||||
-->
|
||||
|
||||
# HTTP basic authentication
|
||||
|
||||
Your [Satis or Toran Proxy](handling-private-packages-with-satis.md) server
|
||||
could be secured with http basic authentication. In order to allow your project
|
||||
to have access to these packages you will have to tell composer how to
|
||||
authenticate with your credentials.
|
||||
|
||||
The simplest way to provide your credentials is providing your set
|
||||
of credentials inline with the repository specification such as:
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "http://extremely:secret@repo.example.org"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This will basically teach composer how to authenticate automatically
|
||||
when reading packages from the provided composer repository.
|
||||
|
||||
This does not work for everybody especially when you don't want to
|
||||
hard code your credentials into your composer.json. There is a second
|
||||
way to provide these details and it is via interaction. If you don't
|
||||
provide the authentication credentials composer will prompt you upon
|
||||
connection to enter the username and password.
|
||||
|
||||
The third way if you want to pre-configure it is via an `auth.json` file
|
||||
located in your `COMPOSER_HOME` or besides your `composer.json`.
|
||||
|
||||
The file should contain a set of hostnames followed each with their own
|
||||
username/password pairs, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"basic-auth": [
|
||||
"repo.example1.org": {
|
||||
"username": "my-username1",
|
||||
"password": "my-secret-password1"
|
||||
},
|
||||
"repo.example2.org": {
|
||||
"username": "my-username2",
|
||||
"password": "my-secret-password2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The main advantage of the auth.json file is that it can be gitignored so
|
||||
that every developer in your team can place their own credentials in there,
|
||||
which makes revokation of credentials much easier than if you all share the
|
||||
same.
|
|
@ -59,6 +59,7 @@ class ClassLoader
|
|||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,15 @@ abstract class Command extends BaseCommand
|
|||
$this->composer = $composer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cached composer instance
|
||||
*/
|
||||
public function resetComposer()
|
||||
{
|
||||
$this->composer = null;
|
||||
$this->getApplication()->resetComposer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IOInterface
|
||||
*/
|
||||
|
|
|
@ -234,8 +234,14 @@ EOT
|
|||
{
|
||||
if (null === $repositoryUrl) {
|
||||
$sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config));
|
||||
} elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION)) {
|
||||
$sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl, new RemoteFilesystem($io, $config)));
|
||||
} elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION) && file_exists($repositoryUrl)) {
|
||||
$json = new JsonFile($repositoryUrl, new RemoteFilesystem($io, $config));
|
||||
$data = $json->read();
|
||||
if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
|
||||
$sourceRepo = new ComposerRepository(array('url' => 'file://' . strtr(realpath($repositoryUrl), '\\', '/')), $io, $config);
|
||||
} else {
|
||||
$sourceRepo = new FilesystemRepository($json);
|
||||
}
|
||||
} elseif (0 === strpos($repositoryUrl, 'http')) {
|
||||
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io, $config);
|
||||
} else {
|
||||
|
|
|
@ -255,7 +255,7 @@ EOT
|
|||
$latest = trim($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/version', false));
|
||||
|
||||
if (Composer::VERSION !== $latest && Composer::VERSION !== '@package_version@') {
|
||||
return '<warning>Your are not running the latest version</warning>';
|
||||
return '<warning>You are not running the latest version</warning>';
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -33,8 +33,9 @@ use Symfony\Component\Process\ExecutableFinder;
|
|||
*/
|
||||
class InitCommand extends Command
|
||||
{
|
||||
protected $repos;
|
||||
|
||||
private $gitConfig;
|
||||
private $repos;
|
||||
private $pool;
|
||||
|
||||
public function parseAuthorString($author)
|
||||
|
|
|
@ -16,6 +16,8 @@ use Composer\Json\JsonFile;
|
|||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -33,6 +35,7 @@ class LicensesCommand extends Command
|
|||
->setDescription('Show information about licenses of dependencies')
|
||||
->setDefinition(array(
|
||||
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The license command displays detailed information about the licenses of
|
||||
|
@ -55,9 +58,10 @@ EOT
|
|||
|
||||
$versionParser = new VersionParser;
|
||||
|
||||
$packages = array();
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
$packages[$package->getName()] = $package;
|
||||
if ($input->getOption('no-dev')) {
|
||||
$packages = $this->filterRequiredPackages($repo, $root);
|
||||
} else {
|
||||
$packages = $this->appendPackages($repo->getPackages(), array());
|
||||
}
|
||||
|
||||
ksort($packages);
|
||||
|
@ -102,4 +106,47 @@ EOT
|
|||
throw new \RuntimeException(sprintf('Unsupported format "%s". See help for supported formats.', $format));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find package requires and child requires
|
||||
*
|
||||
* @param RepositoryInterface $repo
|
||||
* @param PackageInterface $package
|
||||
*/
|
||||
private function filterRequiredPackages(RepositoryInterface $repo, PackageInterface $package, $bucket = array())
|
||||
{
|
||||
$requires = array_keys($package->getRequires());
|
||||
|
||||
$packageListNames = array_keys($bucket);
|
||||
$packages = array_filter(
|
||||
$repo->getPackages(),
|
||||
function ($package) use ($requires, $packageListNames) {
|
||||
return in_array($package->getName(), $requires) && !in_array($package->getName(), $packageListNames);
|
||||
}
|
||||
);
|
||||
|
||||
$bucket = $this->appendPackages($packages, $bucket);
|
||||
|
||||
foreach ($packages as $package) {
|
||||
$bucket = $this->filterRequiredPackages($repo, $package, $bucket);
|
||||
}
|
||||
|
||||
return $bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds packages to the package list
|
||||
*
|
||||
* @param array $packages the list of packages to add
|
||||
* @param array $bucket the list to add packages to
|
||||
* @return array
|
||||
*/
|
||||
public function appendPackages(array $packages, array $bucket)
|
||||
{
|
||||
foreach ($packages as $package) {
|
||||
$bucket[$package->getName()] = $package;
|
||||
}
|
||||
|
||||
return $bucket;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ use Composer\Json\JsonManipulator;
|
|||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
|
||||
/**
|
||||
* @author Jérémy Romey <jeremy@free-agent.fr>
|
||||
|
@ -45,6 +47,7 @@ class RequireCommand extends InitCommand
|
|||
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('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The require command adds required packages to your composer.json and installs them
|
||||
|
@ -78,14 +81,22 @@ EOT
|
|||
}
|
||||
|
||||
$json = new JsonFile($file);
|
||||
$composer = $json->read();
|
||||
$composerDefinition = $json->read();
|
||||
$composerBackup = file_get_contents($json->getPath());
|
||||
|
||||
$composer = $this->getComposer();
|
||||
$repos = $composer->getRepositoryManager()->getRepositories();
|
||||
|
||||
$this->repos = new CompositeRepository(array_merge(
|
||||
array(new PlatformRepository),
|
||||
$repos
|
||||
));
|
||||
|
||||
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'));
|
||||
|
||||
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
|
||||
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
|
||||
$baseRequirements = array_key_exists($requireKey, $composer) ? $composer[$requireKey] : array();
|
||||
$baseRequirements = array_key_exists($requireKey, $composerDefinition) ? $composerDefinition[$requireKey] : array();
|
||||
$requirements = $this->formatRequirements($requirements);
|
||||
|
||||
// validate requirements format
|
||||
|
@ -94,17 +105,19 @@ EOT
|
|||
$versionParser->parseConstraints($constraint);
|
||||
}
|
||||
|
||||
if (!$this->updateFileCleanly($json, $baseRequirements, $requirements, $requireKey, $removeKey)) {
|
||||
$sortPackages = $input->getOption('sort-packages');
|
||||
|
||||
if (!$this->updateFileCleanly($json, $baseRequirements, $requirements, $requireKey, $removeKey, $sortPackages)) {
|
||||
foreach ($requirements as $package => $version) {
|
||||
$baseRequirements[$package] = $version;
|
||||
|
||||
if (isset($composer[$removeKey][$package])) {
|
||||
unset($composer[$removeKey][$package]);
|
||||
if (isset($composerDefinition[$removeKey][$package])) {
|
||||
unset($composerDefinition[$removeKey][$package]);
|
||||
}
|
||||
}
|
||||
|
||||
$composer[$requireKey] = $baseRequirements;
|
||||
$json->write($composer);
|
||||
$composerDefinition[$requireKey] = $baseRequirements;
|
||||
$json->write($composerDefinition);
|
||||
}
|
||||
|
||||
$output->writeln('<info>'.$file.' has been '.($newlyCreated ? 'created' : 'updated').'</info>');
|
||||
|
@ -115,6 +128,7 @@ EOT
|
|||
$updateDevMode = !$input->getOption('update-no-dev');
|
||||
|
||||
// Update packages
|
||||
$this->resetComposer();
|
||||
$composer = $this->getComposer();
|
||||
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
$io = $this->getIO();
|
||||
|
@ -149,14 +163,14 @@ EOT
|
|||
return $status;
|
||||
}
|
||||
|
||||
private function updateFileCleanly($json, array $base, array $new, $requireKey, $removeKey)
|
||||
private function updateFileCleanly($json, array $base, array $new, $requireKey, $removeKey, $sortPackages)
|
||||
{
|
||||
$contents = file_get_contents($json->getPath());
|
||||
|
||||
$manipulator = new JsonManipulator($contents);
|
||||
|
||||
foreach ($new as $package => $constraint) {
|
||||
if (!$manipulator->addLink($requireKey, $package, $constraint)) {
|
||||
if (!$manipulator->addLink($requireKey, $package, $constraint, $sortPackages)) {
|
||||
return false;
|
||||
}
|
||||
if (!$manipulator->removeSubNode($removeKey, $package)) {
|
||||
|
|
|
@ -43,6 +43,7 @@ class SelfUpdateCommand extends Command
|
|||
new InputOption('rollback', 'r', InputOption::VALUE_NONE, 'Revert to an older installation of composer'),
|
||||
new InputOption('clean-backups', null, InputOption::VALUE_NONE, 'Delete old backups during an update. This makes the current version of composer the only backup available after the update'),
|
||||
new InputArgument('version', InputArgument::OPTIONAL, 'The version to update to'),
|
||||
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>self-update</info> command checks getcomposer.org for newer
|
||||
|
@ -105,7 +106,7 @@ EOT
|
|||
|
||||
$output->writeln(sprintf("Updating to version <info>%s</info>.", $updateVersion));
|
||||
$remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar");
|
||||
$remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename);
|
||||
$remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress'));
|
||||
if (!file_exists($tempFilename)) {
|
||||
$output->writeln('<error>The download of the new composer version failed for an unexpected reason</error>');
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ class UpdateCommand extends Command
|
|||
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('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.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>update</info> command reads the composer.json file from the
|
||||
|
@ -121,6 +123,8 @@ EOT
|
|||
->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages'))
|
||||
->setWhitelistDependencies($input->getOption('with-dependencies'))
|
||||
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
|
||||
->setPreferStable($input->getOption('prefer-stable'))
|
||||
->setPreferLowest($input->getOption('prefer-lowest'))
|
||||
;
|
||||
|
||||
if ($input->getOption('no-plugins')) {
|
||||
|
|
|
@ -55,7 +55,7 @@ class Compiler
|
|||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
$this->versionDate = $date->format('Y-m-d H:i:s');
|
||||
|
||||
$process = new Process('git describe --tags HEAD');
|
||||
$process = new Process('git describe --tags --exact-match HEAD');
|
||||
if ($process->run() == 0) {
|
||||
$this->version = trim($process->getOutput());
|
||||
} else {
|
||||
|
@ -212,6 +212,16 @@ class Compiler
|
|||
* the license that is located at the bottom of this file.
|
||||
*/
|
||||
|
||||
// Avoid APC causing random fatal errors per https://github.com/composer/composer/issues/264
|
||||
if (extension_loaded('apc') && ini_get('apc.enable_cli') && ini_get('apc.cache_by_default')) {
|
||||
if (version_compare(phpversion('apc'), '3.0.12', '>=')) {
|
||||
ini_set('apc.cache_by_default', 0);
|
||||
} else {
|
||||
fwrite(STDERR, 'Warning: APC <= 3.0.12 may cause fatal errors when running composer commands.'.PHP_EOL);
|
||||
fwrite(STDERR, 'Update APC, or set apc.enable_cli or apc.cache_by_default to 0 in your php.ini.'.PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
||||
Phar::mapPhar('composer.phar');
|
||||
|
||||
EOF;
|
||||
|
|
|
@ -99,7 +99,8 @@ class Application extends BaseApplication
|
|||
if ($name = $this->getCommandName($input)) {
|
||||
try {
|
||||
$commandName = $this->find($name)->getName();
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
}
|
||||
}
|
||||
if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
|
||||
if (time() > COMPOSER_DEV_WARNING_TIME) {
|
||||
|
@ -176,7 +177,7 @@ class Application extends BaseApplication
|
|||
public function renderException($exception, $output)
|
||||
{
|
||||
try {
|
||||
$composer = $this->getComposer(false);
|
||||
$composer = $this->getComposer(false, true);
|
||||
if ($composer) {
|
||||
$config = $composer->getConfig();
|
||||
|
||||
|
@ -190,6 +191,16 @@ class Application extends BaseApplication
|
|||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
|
||||
$output->writeln('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
|
||||
$output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>');
|
||||
}
|
||||
|
||||
if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
|
||||
$output->writeln('<error>The following exception is caused by a lack of memory and not having swap configured</error>');
|
||||
$output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>');
|
||||
}
|
||||
|
||||
return parent::renderException($exception, $output);
|
||||
}
|
||||
|
||||
|
@ -219,6 +230,14 @@ class Application extends BaseApplication
|
|||
return $this->composer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cached composer instance
|
||||
*/
|
||||
public function resetComposer()
|
||||
{
|
||||
$this->composer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IOInterface
|
||||
*/
|
||||
|
|
|
@ -24,10 +24,12 @@ use Composer\Package\LinkConstraint\VersionConstraint;
|
|||
class DefaultPolicy implements PolicyInterface
|
||||
{
|
||||
private $preferStable;
|
||||
private $preferLowest;
|
||||
|
||||
public function __construct($preferStable = false)
|
||||
public function __construct($preferStable = false, $preferLowest = false)
|
||||
{
|
||||
$this->preferStable = $preferStable;
|
||||
$this->preferLowest = $preferLowest;
|
||||
}
|
||||
|
||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
|
||||
|
@ -195,6 +197,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
|
||||
protected function pruneToBestVersion(Pool $pool, $literals)
|
||||
{
|
||||
$operator = $this->preferLowest ? '<' : '>';
|
||||
$bestLiterals = array($literals[0]);
|
||||
$bestPackage = $pool->literalToPackage($literals[0]);
|
||||
foreach ($literals as $i => $literal) {
|
||||
|
@ -204,7 +207,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
|
||||
$package = $pool->literalToPackage($literal);
|
||||
|
||||
if ($this->versionCompare($package, $bestPackage, '>')) {
|
||||
if ($this->versionCompare($package, $bestPackage, $operator)) {
|
||||
$bestPackage = $package;
|
||||
$bestLiterals = array($literal);
|
||||
} elseif ($this->versionCompare($package, $bestPackage, '==')) {
|
||||
|
|
|
@ -241,7 +241,7 @@ class RuleSetGenerator
|
|||
|
||||
if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
|
||||
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createRequireRule($package, array($provider), Rule::RULE_PACKAGE_ALIAS, $package));
|
||||
} elseif (!$this->obsoleteImpossibleForAlias($package, $provider) && $package->id <= $provider->id) {
|
||||
} elseif (!$this->obsoleteImpossibleForAlias($package, $provider)) {
|
||||
$reason = ($package->getName() == $provider->getName()) ? Rule::RULE_PACKAGE_SAME_NAME : Rule::RULE_PACKAGE_IMPLICIT_OBSOLETES;
|
||||
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createConflictRule($package, $provider, $reason, $package));
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ class EventDispatcher
|
|||
$return = 0;
|
||||
foreach ($listeners as $callable) {
|
||||
if (!is_string($callable) && is_callable($callable)) {
|
||||
$event = $this->checkListenerExpectedEvent($callable, $event);
|
||||
$return = false === call_user_func($callable, $event) ? 1 : 0;
|
||||
} elseif ($this->isPhpScript($callable)) {
|
||||
$className = substr($callable, 0, strpos($callable, '::'));
|
||||
|
@ -200,9 +201,43 @@ class EventDispatcher
|
|||
*/
|
||||
protected function executeEventPhpScript($className, $methodName, Event $event)
|
||||
{
|
||||
$event = $this->checkListenerExpectedEvent(array($className, $methodName), $event);
|
||||
|
||||
return $className::$methodName($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $target
|
||||
* @param Event $event
|
||||
* @return Event|CommandEvent
|
||||
*/
|
||||
protected function checkListenerExpectedEvent($target, Event $event)
|
||||
{
|
||||
if (!$event instanceof Script\Event) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
try {
|
||||
$reflected = new \ReflectionParameter($target, 0);
|
||||
} catch (\Exception $e) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
$typehint = $reflected->getClass();
|
||||
|
||||
if (!$typehint instanceof \ReflectionClass) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
$expected = $typehint->getName();
|
||||
|
||||
if (!$event instanceof $expected && $expected === 'Composer\Script\CommandEvent') {
|
||||
$event = new CommandEvent($event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments());
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for a particular event
|
||||
*
|
||||
|
|
|
@ -107,6 +107,8 @@ class Installer
|
|||
protected $update = false;
|
||||
protected $runScripts = true;
|
||||
protected $ignorePlatformReqs = false;
|
||||
protected $preferStable = false;
|
||||
protected $preferLowest = false;
|
||||
/**
|
||||
* Array of package names/globs flagged for update
|
||||
*
|
||||
|
@ -307,7 +309,8 @@ class Installer
|
|||
$aliases,
|
||||
$this->package->getMinimumStability(),
|
||||
$this->package->getStabilityFlags(),
|
||||
$this->package->getPreferStable()
|
||||
$this->preferStable || $this->package->getPreferStable(),
|
||||
$this->preferLowest
|
||||
);
|
||||
if ($updatedLock) {
|
||||
$this->io->write('<info>Writing lock file</info>');
|
||||
|
@ -694,16 +697,21 @@ class Installer
|
|||
private function createPolicy()
|
||||
{
|
||||
$preferStable = null;
|
||||
$preferLowest = null;
|
||||
if (!$this->update && $this->locker->isLocked()) {
|
||||
$preferStable = $this->locker->getPreferStable();
|
||||
$preferLowest = $this->locker->getPreferLowest();
|
||||
}
|
||||
// old lock file without prefer stable will return null
|
||||
// old lock file without prefer stable/lowest will return null
|
||||
// so in this case we use the composer.json info
|
||||
if (null === $preferStable) {
|
||||
$preferStable = $this->package->getPreferStable();
|
||||
$preferStable = $this->preferStable || $this->package->getPreferStable();
|
||||
}
|
||||
if (null === $preferLowest) {
|
||||
$preferLowest = $this->preferLowest;
|
||||
}
|
||||
|
||||
return new DefaultPolicy($preferStable);
|
||||
return new DefaultPolicy($preferStable, $preferLowest);
|
||||
}
|
||||
|
||||
private function createRequest(Pool $pool, RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
|
||||
|
@ -1244,6 +1252,32 @@ class Installer
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should packages be prefered in a stable version when updating?
|
||||
*
|
||||
* @param boolean $preferStable
|
||||
* @return Installer
|
||||
*/
|
||||
public function setPreferStable($preferStable = true)
|
||||
{
|
||||
$this->preferStable = (boolean) $preferStable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should packages be prefered in a lowest version when updating?
|
||||
*
|
||||
* @param boolean $preferLowest
|
||||
* @return Installer
|
||||
*/
|
||||
public function setPreferLowest($preferLowest = true)
|
||||
{
|
||||
$this->preferLowest = (boolean) $preferLowest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables plugins.
|
||||
*
|
||||
|
|
|
@ -31,7 +31,7 @@ class JsonManipulator
|
|||
if (!self::$RECURSE_BLOCKS) {
|
||||
self::$RECURSE_BLOCKS = '(?:[^{}]*|\{(?:[^{}]*|\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\})*\})*';
|
||||
self::$RECURSE_ARRAYS = '(?:[^\]]*|\[(?:[^\]]*|\[(?:[^\]]*|\[(?:[^\]]*|\[[^\]]*\])*\])*\])*\]|'.self::$RECURSE_BLOCKS.')*';
|
||||
self::$JSON_STRING = '"(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f\\\\"])+"';
|
||||
self::$JSON_STRING = '"(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f\\\\"])*"';
|
||||
self::$JSON_VALUE = '(?:[0-9.]+|null|true|false|'.self::$JSON_STRING.'|\['.self::$RECURSE_ARRAYS.'\]|\{'.self::$RECURSE_BLOCKS.'\})';
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ class JsonManipulator
|
|||
return $this->contents . $this->newline;
|
||||
}
|
||||
|
||||
public function addLink($type, $package, $constraint)
|
||||
public function addLink($type, $package, $constraint, $sortPackages = false)
|
||||
{
|
||||
$decoded = JsonFile::parseJson($this->contents);
|
||||
|
||||
|
@ -90,6 +90,13 @@ class JsonManipulator
|
|||
}
|
||||
}
|
||||
|
||||
if (true === $sortPackages) {
|
||||
$requirements = json_decode($links, true);
|
||||
|
||||
ksort($requirements);
|
||||
$links = $this->format($requirements);
|
||||
}
|
||||
|
||||
$this->contents = $matches[1] . $matches[2] . $links . $matches[4];
|
||||
|
||||
return true;
|
||||
|
|
|
@ -137,7 +137,7 @@ class ArchiveManager
|
|||
$sourcePath = realpath('.');
|
||||
} else {
|
||||
// Directory used to download the sources
|
||||
$sourcePath = sys_get_temp_dir().'/composer_archiver/arch'.uniqid();
|
||||
$sourcePath = sys_get_temp_dir().'/composer_archive'.uniqid();
|
||||
$filesystem->ensureDirectoryExists($sourcePath);
|
||||
|
||||
// Download sources
|
||||
|
@ -154,7 +154,7 @@ class ArchiveManager
|
|||
}
|
||||
|
||||
// Create the archive
|
||||
$tempTarget = sys_get_temp_dir().'/composer_archiver/arch'.uniqid().'.'.$format;
|
||||
$tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format;
|
||||
$filesystem->ensureDirectoryExists(dirname($tempTarget));
|
||||
|
||||
$archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes());
|
||||
|
@ -164,6 +164,7 @@ class ArchiveManager
|
|||
if (!$package instanceof RootPackageInterface) {
|
||||
$filesystem->removeDirectory($sourcePath);
|
||||
}
|
||||
$filesystem->remove($tempTarget);
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ abstract class BasePackage implements PackageInterface
|
|||
protected $repository;
|
||||
protected $transportOptions;
|
||||
|
||||
|
||||
/**
|
||||
* All descendants' constructors should call this parent constructor
|
||||
*
|
||||
|
|
|
@ -194,6 +194,6 @@ class CompletePackage extends Package implements CompletePackageInterface
|
|||
*/
|
||||
public function getReplacementPackage()
|
||||
{
|
||||
return is_string($this->abandoned)? $this->abandoned : null;
|
||||
return is_string($this->abandoned) ? $this->abandoned : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,6 +182,15 @@ class Locker
|
|||
return isset($lockData['prefer-stable']) ? $lockData['prefer-stable'] : null;
|
||||
}
|
||||
|
||||
public function getPreferLowest()
|
||||
{
|
||||
$lockData = $this->getLockData();
|
||||
|
||||
// return null if not set to allow caller logic to choose the
|
||||
// right behavior since old lock files have no prefer-lowest
|
||||
return isset($lockData['prefer-lowest']) ? $lockData['prefer-lowest'] : null;
|
||||
}
|
||||
|
||||
public function getAliases()
|
||||
{
|
||||
$lockData = $this->getLockData();
|
||||
|
@ -213,10 +222,11 @@ class Locker
|
|||
* @param string $minimumStability
|
||||
* @param array $stabilityFlags
|
||||
* @param bool $preferStable
|
||||
* @param bool $preferLowest
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable)
|
||||
public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest)
|
||||
{
|
||||
$lock = array(
|
||||
'_readme' => array('This file locks the dependencies of your project to a known state',
|
||||
|
@ -229,6 +239,7 @@ class Locker
|
|||
'minimum-stability' => $minimumStability,
|
||||
'stability-flags' => $stabilityFlags,
|
||||
'prefer-stable' => $preferStable,
|
||||
'prefer-lowest' => $preferLowest,
|
||||
);
|
||||
|
||||
foreach ($aliases as $package => $versions) {
|
||||
|
|
|
@ -103,6 +103,11 @@ class VersionParser
|
|||
$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';
|
||||
|
@ -178,10 +183,10 @@ class VersionParser
|
|||
return $this->normalize($name);
|
||||
}
|
||||
|
||||
if (preg_match('#^v?(\d+)(\.(?:\d+|[x*]))?(\.(?:\d+|[x*]))?(\.(?:\d+|[x*]))?$#i', $name, $matches)) {
|
||||
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('*', 'x', $matches[$i]) : '.x';
|
||||
$version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
|
||||
}
|
||||
|
||||
return str_replace('x', '9999999', $version).'-dev';
|
||||
|
@ -230,11 +235,10 @@ class VersionParser
|
|||
$constraints = $match[1];
|
||||
}
|
||||
|
||||
$orConstraints = preg_split('{\s*\|\s*}', trim($constraints));
|
||||
$orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
|
||||
$orGroups = array();
|
||||
foreach ($orConstraints as $constraints) {
|
||||
$andConstraints = preg_split('{\s*,\s*}', $constraints);
|
||||
|
||||
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
|
||||
if (count($andConstraints) > 1) {
|
||||
$constraintObjects = array();
|
||||
foreach ($andConstraints as $constraint) {
|
||||
|
@ -273,16 +277,18 @@ class VersionParser
|
|||
}
|
||||
}
|
||||
|
||||
if (preg_match('{^[x*](\.[x*])*$}i', $constraint)) {
|
||||
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('{^~>?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?'.self::$modifierRegex.'?$}i', $constraint, $matches)) {
|
||||
if (preg_match('{^~>?'.$versionRegex.'$}i', $constraint, $matches)) {
|
||||
if (substr($constraint, 0, 2) === '~>') {
|
||||
throw new \UnexpectedValueException(
|
||||
'Could not parse version constraint '.$constraint.': '.
|
||||
|
@ -329,8 +335,39 @@ class VersionParser
|
|||
);
|
||||
}
|
||||
|
||||
// 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+))?\.[x*]$}', $constraint, $matches)) {
|
||||
if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', $constraint, $matches)) {
|
||||
if (isset($matches[3]) && '' !== $matches[3]) {
|
||||
$position = 3;
|
||||
} elseif (isset($matches[2]) && '' !== $matches[2]) {
|
||||
|
@ -352,6 +389,33 @@ class VersionParser
|
|||
);
|
||||
}
|
||||
|
||||
// match hyphen constraints
|
||||
if (preg_match('{^(?P<from>'.$versionRegex.') +- +(?P<to>'.$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);
|
||||
|
||||
$highVersion = $matches[10];
|
||||
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 {
|
||||
|
@ -360,7 +424,7 @@ class VersionParser
|
|||
if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') {
|
||||
$version .= '-' . $stabilityModifier;
|
||||
} elseif ('<' === $matches[1]) {
|
||||
if (!preg_match('/-stable$/', strtolower($matches[2]))) {
|
||||
if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
|
||||
$version .= '-dev';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,10 +103,22 @@ class VersionSelector
|
|||
// attempt to transform 2.1.1 to 2.1
|
||||
// this allows you to upgrade through minor versions
|
||||
$semanticVersionParts = explode('.', $version);
|
||||
$op = '~';
|
||||
|
||||
// check to see if we have a semver-looking version
|
||||
if (count($semanticVersionParts) == 4 && preg_match('{^0\D?}', $semanticVersionParts[3])) {
|
||||
// remove the last parts (i.e. the patch version number and any extra)
|
||||
if ($semanticVersionParts[0] === '0') {
|
||||
if ($semanticVersionParts[1] === '0') {
|
||||
$semanticVersionParts[3] = '*';
|
||||
} else {
|
||||
$semanticVersionParts[2] = '*';
|
||||
unset($semanticVersionParts[3]);
|
||||
}
|
||||
$op = '';
|
||||
} else {
|
||||
unset($semanticVersionParts[2], $semanticVersionParts[3]);
|
||||
}
|
||||
$version = implode('.', $semanticVersionParts);
|
||||
} else {
|
||||
return $prettyVersion;
|
||||
|
@ -118,7 +130,7 @@ class VersionSelector
|
|||
}
|
||||
|
||||
// 2.1 -> ~2.1
|
||||
return '~'.$version;
|
||||
return $op.$version;
|
||||
}
|
||||
|
||||
private function getParser()
|
||||
|
|
|
@ -28,12 +28,13 @@ use Composer\DependencyResolver\Pool;
|
|||
* Plugin manager
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class PluginManager
|
||||
{
|
||||
protected $composer;
|
||||
protected $io;
|
||||
protected $globalRepository;
|
||||
protected $globalComposer;
|
||||
protected $versionParser;
|
||||
|
||||
protected $plugins = array();
|
||||
|
@ -44,15 +45,15 @@ class PluginManager
|
|||
/**
|
||||
* Initializes plugin manager
|
||||
*
|
||||
* @param Composer $composer
|
||||
* @param IOInterface $io
|
||||
* @param RepositoryInterface $globalRepository
|
||||
* @param Composer $composer
|
||||
* @param Composer $globalComposer
|
||||
*/
|
||||
public function __construct(Composer $composer, IOInterface $io, RepositoryInterface $globalRepository = null)
|
||||
public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null)
|
||||
{
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->globalRepository = $globalRepository;
|
||||
$this->composer = $composer;
|
||||
$this->globalComposer = $globalComposer;
|
||||
$this->versionParser = new VersionParser();
|
||||
}
|
||||
|
||||
|
@ -62,12 +63,12 @@ class PluginManager
|
|||
public function loadInstalledPlugins()
|
||||
{
|
||||
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
||||
if ($repo) {
|
||||
$this->loadRepository($repo);
|
||||
}
|
||||
if ($this->globalRepository) {
|
||||
$this->loadRepository($this->globalRepository);
|
||||
if ($globalRepo) {
|
||||
$this->loadRepository($globalRepo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,11 +207,13 @@ class PluginManager
|
|||
}
|
||||
$classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
|
||||
|
||||
$pool = new Pool('dev');
|
||||
$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
||||
|
||||
$pool = new Pool('dev');
|
||||
$pool->addRepository($localRepo);
|
||||
if ($this->globalRepository) {
|
||||
$pool->addRepository($this->globalRepository);
|
||||
if ($globalRepo) {
|
||||
$pool->addRepository($globalRepo);
|
||||
}
|
||||
|
||||
$autoloadPackages = array($package->getName() => $package);
|
||||
|
@ -219,7 +222,7 @@ class PluginManager
|
|||
$generator = $this->composer->getAutoloadGenerator();
|
||||
$autoloads = array();
|
||||
foreach ($autoloadPackages as $autoloadPackage) {
|
||||
$downloadPath = $this->getInstallPath($autoloadPackage, ($this->globalRepository && $this->globalRepository->hasPackage($autoloadPackage)));
|
||||
$downloadPath = $this->getInstallPath($autoloadPackage, ($globalRepo && $globalRepo->hasPackage($autoloadPackage)));
|
||||
$autoloads[] = array($autoloadPackage, $downloadPath);
|
||||
}
|
||||
|
||||
|
@ -261,9 +264,6 @@ class PluginManager
|
|||
return $this->composer->getInstallationManager()->getInstallPath($package);
|
||||
}
|
||||
|
||||
$targetDir = $package->getTargetDir();
|
||||
$vendorDir = $this->composer->getConfig()->get('home').'/vendor';
|
||||
|
||||
return ($vendorDir ? $vendorDir.'/' : '').$package->getPrettyName().($targetDir ? '/'.$targetDir : '');
|
||||
return $this->globalComposer->getInstallationManager()->getInstallPath($package);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ class ComposerRepository extends ArrayRepository
|
|||
$this->config = $config;
|
||||
$this->options = $repoConfig['options'];
|
||||
$this->url = $repoConfig['url'];
|
||||
$this->baseUrl = rtrim(preg_replace('{^(.*)(?:/packages.json)?(?:[?#].*)?$}', '$1', $this->url), '/');
|
||||
$this->baseUrl = rtrim(preg_replace('{^(.*)(?:/[^/\\]+.json)?(?:[?#].*)?$}', '$1', $this->url), '/');
|
||||
$this->io = $io;
|
||||
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
|
||||
$this->loader = new ArrayLoader();
|
||||
|
@ -395,7 +395,7 @@ class ComposerRepository extends ArrayRepository
|
|||
|
||||
$jsonUrlParts = parse_url($this->url);
|
||||
|
||||
if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '/packages.json')) {
|
||||
if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
|
||||
$jsonUrl = $this->url;
|
||||
} else {
|
||||
$jsonUrl = $this->url . '/packages.json';
|
||||
|
|
|
@ -93,7 +93,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
|
|||
|
||||
$composer = JsonFile::parseJson($composer, $resource);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier;
|
||||
$changeset = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$composer['time'] = $changeset['timestamp'];
|
||||
|
|
|
@ -156,7 +156,7 @@ class GitDriver extends VcsDriver
|
|||
|
||||
$composer = JsonFile::parseJson($composer, $resource);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$this->process->execute(sprintf('git log -1 --format=%%at %s', ProcessExecutor::escape($identifier)), $output, $this->repoDir);
|
||||
$date = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
|
||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||
|
@ -227,7 +227,7 @@ class GitDriver extends VcsDriver
|
|||
if (Filesystem::isLocalPath($url)) {
|
||||
$url = Filesystem::getPlatformPath($url);
|
||||
if (!is_dir($url)) {
|
||||
throw new \RuntimeException('Directory does not exist: '.$url);
|
||||
return false;
|
||||
}
|
||||
|
||||
$process = new ProcessExecutor($io);
|
||||
|
|
|
@ -171,7 +171,7 @@ class GitHubDriver extends VcsDriver
|
|||
if ($composer) {
|
||||
$composer = JsonFile::parseJson($composer, $resource);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
|
||||
$commit = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$composer['time'] = $commit['commit']['committer']['date'];
|
||||
|
|
|
@ -102,7 +102,7 @@ class HgBitbucketDriver extends VcsDriver
|
|||
|
||||
$composer = JsonFile::parseJson($repoData['data'], $resource);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier;
|
||||
$changeset = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$composer['time'] = $changeset['timestamp'];
|
||||
|
|
|
@ -124,7 +124,7 @@ class HgDriver extends VcsDriver
|
|||
|
||||
$composer = JsonFile::parseJson($composer, $identifier);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$this->process->execute(sprintf('hg log --template "{date|rfc3339date}" -r %s', ProcessExecutor::escape($identifier)), $output, $this->repoDir);
|
||||
$date = new \DateTime(trim($output), new \DateTimeZone('UTC'));
|
||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||
|
@ -200,7 +200,7 @@ class HgDriver extends VcsDriver
|
|||
if (Filesystem::isLocalPath($url)) {
|
||||
$url = Filesystem::getPlatformPath($url);
|
||||
if (!is_dir($url)) {
|
||||
throw new \RuntimeException('Directory does not exist: '.$url);
|
||||
return false;
|
||||
}
|
||||
|
||||
$process = new ProcessExecutor();
|
||||
|
|
|
@ -148,7 +148,7 @@ class SvnDriver extends VcsDriver
|
|||
|
||||
$composer = JsonFile::parseJson($output, $this->baseUrl . $resource . $rev);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
if (empty($composer['time'])) {
|
||||
$output = $this->execute('svn info', $this->baseUrl . $path . $rev);
|
||||
foreach ($this->process->splitLines($output) as $line) {
|
||||
if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
|
||||
|
|
|
@ -385,15 +385,19 @@ class RemoteFilesystem
|
|||
|
||||
protected function getOptionsForUrl($originUrl, $additionalOptions)
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$phpVersion = 'HHVM ' . HHVM_VERSION;
|
||||
} else {
|
||||
$phpVersion = 'PHP ' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
|
||||
}
|
||||
|
||||
$headers = array(
|
||||
sprintf(
|
||||
'User-Agent: Composer/%s (%s; %s; PHP %s.%s.%s)',
|
||||
'User-Agent: Composer/%s (%s; %s; %s)',
|
||||
Composer::VERSION === '@package_version@' ? 'source' : Composer::VERSION,
|
||||
php_uname('s'),
|
||||
php_uname('r'),
|
||||
PHP_MAJOR_VERSION,
|
||||
PHP_MINOR_VERSION,
|
||||
PHP_RELEASE_VERSION
|
||||
$phpVersion
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -43,6 +43,19 @@ final class StreamContextFactory
|
|||
$proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
|
||||
}
|
||||
|
||||
// Override with HTTPS proxy if present and URL is https
|
||||
if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
|
||||
$proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']);
|
||||
}
|
||||
|
||||
// Remove proxy if URL matches no_proxy directive
|
||||
if (!empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) {
|
||||
$pattern = new NoProxyPattern($_SERVER['no_proxy']);
|
||||
if ($pattern->test($url)) {
|
||||
unset($proxy);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($proxy)) {
|
||||
$proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : '';
|
||||
$proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';
|
||||
|
@ -64,16 +77,6 @@ final class StreamContextFactory
|
|||
|
||||
$options['http']['proxy'] = $proxyURL;
|
||||
|
||||
// Handle no_proxy directive
|
||||
if (!empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) {
|
||||
$pattern = new NoProxyPattern($_SERVER['no_proxy']);
|
||||
if ($pattern->test($url)) {
|
||||
unset($options['http']['proxy']);
|
||||
}
|
||||
}
|
||||
|
||||
// add request_fulluri and authentication if we still have a proxy to connect to
|
||||
if (!empty($options['http']['proxy'])) {
|
||||
// enabled request_fulluri unless it is explicitly disabled
|
||||
switch (parse_url($url, PHP_URL_SCHEME)) {
|
||||
case 'http': // default request_fulluri to true
|
||||
|
@ -90,6 +93,15 @@ final class StreamContextFactory
|
|||
break;
|
||||
}
|
||||
|
||||
// add SNI opts for https URLs
|
||||
if ('https' === parse_url($url, PHP_URL_SCHEME)) {
|
||||
$options['ssl']['SNI_enabled'] = true;
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '<')) {
|
||||
$options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST);
|
||||
}
|
||||
}
|
||||
|
||||
// handle proxy auth if present
|
||||
if (isset($proxy['user'])) {
|
||||
$auth = urldecode($proxy['user']);
|
||||
if (isset($proxy['pass'])) {
|
||||
|
@ -108,7 +120,6 @@ final class StreamContextFactory
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$options = array_replace_recursive($options, $defaultOptions);
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ class CacheTest extends TestCase
|
|||
|
||||
public function setUp()
|
||||
{
|
||||
if (getenv('TRAVIS')) {
|
||||
$this->markTestSkipped('Test causes intermittent failures on Travis');
|
||||
}
|
||||
|
||||
$this->root = sys_get_temp_dir() . '/composer_testdir';
|
||||
$this->ensureDirectoryExistsAndClear($this->root);
|
||||
|
||||
|
|
|
@ -247,4 +247,20 @@ class DefaultPolicyTest extends TestCase
|
|||
|
||||
return $map;
|
||||
}
|
||||
|
||||
public function testSelectLowest()
|
||||
{
|
||||
$policy = new DefaultPolicy(false, true);
|
||||
|
||||
$this->repo->addPackage($packageA1 = $this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0'));
|
||||
$this->pool->addRepository($this->repo);
|
||||
|
||||
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||
$expected = array($packageA1->getId());
|
||||
|
||||
$selected = $policy->selectPreferedPackages($this->pool, array(), $literals);
|
||||
|
||||
$this->assertEquals($expected, $selected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use Composer\EventDispatcher\EventDispatcher;
|
|||
use Composer\Installer\InstallerEvents;
|
||||
use Composer\TestCase;
|
||||
use Composer\Script\ScriptEvents;
|
||||
use Composer\Script\CommandEvent;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
class EventDispatcherTest extends TestCase
|
||||
|
@ -28,7 +29,7 @@ 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())
|
||||
|
@ -38,6 +39,26 @@ class EventDispatcherTest extends TestCase
|
|||
$dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false);
|
||||
}
|
||||
|
||||
public function testDispatcherCanConvertScriptEventToCommandEventForListener()
|
||||
{
|
||||
$io = $this->getMock('Composer\IO\IOInterface');
|
||||
$dispatcher = $this->getDispatcherStubForListenersTest(array(
|
||||
'Composer\Test\EventDispatcher\EventDispatcherTest::expectsCommandEvent'
|
||||
), $io);
|
||||
|
||||
$this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
|
||||
}
|
||||
|
||||
public function testDispatcherDoesNotAttemptConversionForListenerWithoutTypehint()
|
||||
{
|
||||
$io = $this->getMock('Composer\IO\IOInterface');
|
||||
$dispatcher = $this->getDispatcherStubForListenersTest(array(
|
||||
'Composer\Test\EventDispatcher\EventDispatcherTest::expectsVariableEvent'
|
||||
), $io);
|
||||
|
||||
$this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidCommands
|
||||
* @param string $command
|
||||
|
@ -205,6 +226,16 @@ class EventDispatcherTest extends TestCase
|
|||
throw new \RuntimeException();
|
||||
}
|
||||
|
||||
public static function expectsCommandEvent(CommandEvent $event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function expectsVariableEvent($event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function someMethod()
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -48,6 +48,7 @@ install --prefer-dist
|
|||
"a/a": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ Requirements from the composer file are not installed if the lock file is presen
|
|||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
--TEST--
|
||||
Install from a lock file that deleted a package
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "whitelisted", "version": "1.1.0" },
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "fixed-dependency": "1.0.0", "old-dependency": "1.0.0" } },
|
||||
{ "name": "fixed-dependency", "version": "1.1.0" },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"whitelisted": "1.*",
|
||||
"fixed-dependency": "1.*"
|
||||
}
|
||||
}
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "whitelisted", "version": "1.1.0" },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "old-dependency": "1.0.0", "fixed-dependency": "1.0.0" } },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--RUN--
|
||||
install
|
||||
--EXPECT--
|
||||
Uninstalling old-dependency (1.0.0)
|
||||
Updating whitelisted (1.0.0) to whitelisted (1.1.0)
|
|
@ -33,7 +33,8 @@ Installing an old alias that doesn't exist anymore from a lock is possible
|
|||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
|
|
|
@ -36,6 +36,7 @@ Partial update from lock file should apply lock file and downgrade unstable pack
|
|||
"b/unstable": 15
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
@ -59,6 +60,7 @@ update c/uptodate
|
|||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ Partial update from lock file should update everything to the state of the lock,
|
|||
"b/unstable": 15
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
@ -59,6 +60,7 @@ update b/unstable
|
|||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ update b/unstable
|
|||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ Update aliased package does not mess up the lock file
|
|||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
|
@ -66,6 +67,7 @@ update
|
|||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
--TEST--
|
||||
Updates packages to their lowest stable version
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "a/a", "version": "1.0.0-rc1" },
|
||||
{ "name": "a/a", "version": "1.0.1" },
|
||||
{ "name": "a/a", "version": "1.1.0" },
|
||||
|
||||
{ "name": "a/b", "version": "1.0.0" },
|
||||
{ "name": "a/b", "version": "1.0.1" },
|
||||
{ "name": "a/b", "version": "2.0.0" },
|
||||
|
||||
{ "name": "a/c", "version": "1.0.0" },
|
||||
{ "name": "a/c", "version": "2.0.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"a/a": "~1.0@dev",
|
||||
"a/c": "2.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"a/b": "*"
|
||||
}
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{ "name": "a/a", "version": "1.0.0-rc1" },
|
||||
{ "name": "a/c", "version": "2.0.0" },
|
||||
{ "name": "a/b", "version": "1.0.1" }
|
||||
]
|
||||
--RUN--
|
||||
update --prefer-lowest --prefer-stable
|
||||
--EXPECT--
|
||||
Updating a/a (1.0.0-rc1) to a/a (1.0.1)
|
||||
Updating a/b (1.0.1) to a/b (1.0.0)
|
|
@ -32,7 +32,8 @@ Limited update takes rules from lock if available, and not from the installed re
|
|||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
--TEST--
|
||||
Update with a package whitelist removes unused packages
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "whitelisted", "version": "1.1.0" },
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "fixed-dependency": "1.0.0", "old-dependency": "1.0.0" } },
|
||||
{ "name": "fixed-dependency", "version": "1.1.0" },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"whitelisted": "1.*",
|
||||
"fixed-dependency": "1.*"
|
||||
}
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "old-dependency": "1.0.0", "fixed-dependency": "1.0.0" } },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--RUN--
|
||||
update --with-dependencies whitelisted
|
||||
--EXPECT--
|
||||
Uninstalling old-dependency (1.0.0)
|
||||
Updating whitelisted (1.0.0) to whitelisted (1.1.0)
|
|
@ -20,7 +20,8 @@ Installing locked dev packages should remove old dependencies
|
|||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
|
|
|
@ -32,7 +32,8 @@ Updating a dev package for new reference updates the url and reference
|
|||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
|
@ -59,6 +60,7 @@ update
|
|||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
|
@ -217,6 +217,8 @@ class InstallerTest extends TestCase
|
|||
->setDryRun($input->getOption('dry-run'))
|
||||
->setUpdateWhitelist($input->getArgument('packages'))
|
||||
->setWhitelistDependencies($input->getOption('with-dependencies'))
|
||||
->setPreferStable($input->getOption('prefer-stable'))
|
||||
->setPreferLowest($input->getOption('prefer-lowest'))
|
||||
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'));
|
||||
|
||||
return $installer->run();
|
||||
|
@ -292,7 +294,7 @@ class InstallerTest extends TestCase
|
|||
|
||||
// Change paths like file://foobar to file:///path/to/fixtures
|
||||
if (preg_match('{^file://[^/]}', $repo['url'])) {
|
||||
$repo['url'] = "file://${fixturesDir}/" . substr($repo['url'], 7);
|
||||
$repo['url'] = 'file://' . strtr($fixturesDir, '\\', '/') . '/' . substr($repo['url'], 7);
|
||||
}
|
||||
|
||||
unset($repo);
|
||||
|
|
|
@ -73,6 +73,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
|
|||
),
|
||||
array(
|
||||
'{
|
||||
"empty": "",
|
||||
"require": {
|
||||
"foo": "bar"
|
||||
}
|
||||
|
@ -81,6 +82,7 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
|
|||
'vendor/baz',
|
||||
'qux',
|
||||
'{
|
||||
"empty": "",
|
||||
"require": {
|
||||
"foo": "bar",
|
||||
"vendor/baz": "qux"
|
||||
|
@ -281,6 +283,58 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerAddLinkAndSortPackages
|
||||
*/
|
||||
public function testAddLinkAndSortPackages($json, $type, $package, $constraint, $sortPackages, $expected)
|
||||
{
|
||||
$manipulator = new JsonManipulator($json);
|
||||
$this->assertTrue($manipulator->addLink($type, $package, $constraint, $sortPackages));
|
||||
$this->assertEquals($expected, $manipulator->getContents());
|
||||
}
|
||||
|
||||
public function providerAddLinkAndSortPackages()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'{
|
||||
"require": {
|
||||
"vendor/baz": "qux"
|
||||
}
|
||||
}',
|
||||
'require',
|
||||
'foo',
|
||||
'bar',
|
||||
true,
|
||||
'{
|
||||
"require": {
|
||||
"foo": "bar",
|
||||
"vendor/baz": "qux"
|
||||
}
|
||||
}
|
||||
'
|
||||
),
|
||||
array(
|
||||
'{
|
||||
"require": {
|
||||
"vendor/baz": "qux"
|
||||
}
|
||||
}',
|
||||
'require',
|
||||
'foo',
|
||||
'bar',
|
||||
false,
|
||||
'{
|
||||
"require": {
|
||||
"vendor/baz": "qux",
|
||||
"foo": "bar"
|
||||
}
|
||||
}
|
||||
'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider removeSubNodeProvider
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Config;
|
|||
use Composer\Factory;
|
||||
use Composer\Repository;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Repository\WritableRepositoryInterface;
|
||||
use Composer\Installer;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
|
@ -46,7 +47,7 @@ class FactoryMock extends Factory
|
|||
{
|
||||
}
|
||||
|
||||
protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im)
|
||||
protected function purgePackages(WritableRepositoryInterface $repo, Installer\InstallationManager $im)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,9 +135,10 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
'platform' => array(),
|
||||
'platform-dev' => array(),
|
||||
'prefer-stable' => false,
|
||||
'prefer-lowest' => false,
|
||||
));
|
||||
|
||||
$locker->setLockData(array($package1, $package2), array(), array(), array(), array(), 'dev', array(), false);
|
||||
$locker->setLockData(array($package1, $package2), array(), array(), array(), array(), 'dev', array(), false, false);
|
||||
}
|
||||
|
||||
public function testLockBadPackages()
|
||||
|
@ -156,7 +157,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->setExpectedException('LogicException');
|
||||
|
||||
$locker->setLockData(array($package1), array(), array(), array(), array(), 'dev', array(), false);
|
||||
$locker->setLockData(array($package1), array(), array(), array(), array(), 'dev', array(), false, false);
|
||||
}
|
||||
|
||||
public function testIsFresh()
|
||||
|
|
|
@ -90,6 +90,7 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
'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'),
|
||||
|
@ -109,6 +110,10 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
'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'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -130,6 +135,7 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
'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'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -208,7 +214,7 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
'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()),
|
||||
'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')),
|
||||
|
@ -221,6 +227,8 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
'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')),
|
||||
|
@ -253,7 +261,7 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
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.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')),
|
||||
);
|
||||
|
@ -291,16 +299,112 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
);
|
||||
}
|
||||
|
||||
public function testParseConstraintsMulti()
|
||||
/**
|
||||
* @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.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')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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('>2.0,<=3.0'));
|
||||
$this->assertSame((string) $multi, (string) $parser->parseConstraints($constraint));
|
||||
}
|
||||
|
||||
public function testParseConstraintsMultiDisjunctiveHasPrioOverConjuctive()
|
||||
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');
|
||||
|
@ -308,7 +412,16 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
$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('>2.0,<2.0.5 | >2.0.6'));
|
||||
$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()
|
||||
|
@ -335,6 +448,9 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
|
|||
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'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,10 @@ class VersionSelectorTest extends \PHPUnit_Framework_TestCase
|
|||
array('v1.2.1', false, 'stable', '~1.2'),
|
||||
array('3.1.2-pl2', false, 'stable', '~3.1'),
|
||||
array('3.1.2-patch', false, 'stable', '~3.1'),
|
||||
// for non-stable versions, we add ~, but don't try the (1.2.1 -> 1.2) transformation
|
||||
array('0.1.0', false, 'stable', '0.1.*'),
|
||||
array('0.1.3', false, 'stable', '0.1.*'),
|
||||
array('0.0.3', false, 'stable', '0.0.3.*'),
|
||||
array('0.0.3-alpha', false, 'alpha', '0.0.3.*@alpha'),
|
||||
array('2.0-beta.1', false, 'beta', '~2.0@beta'),
|
||||
array('3.1.2-alpha5', false, 'alpha', '~3.1@alpha'),
|
||||
array('3.0-RC2', false, 'RC', '~3.0@RC'),
|
||||
|
|
|
@ -76,7 +76,7 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
|
|||
$this->composer->setInstallationManager($im);
|
||||
$this->composer->setAutoloadGenerator($this->autoloadGenerator);
|
||||
|
||||
$this->pm = new PluginManager($this->composer, $this->io);
|
||||
$this->pm = new PluginManager($this->io, $this->composer);
|
||||
$this->composer->setPluginManager($this->pm);
|
||||
|
||||
$config->merge(array(
|
||||
|
|
|
@ -20,6 +20,8 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
unset($_SERVER['HTTP_PROXY']);
|
||||
unset($_SERVER['http_proxy']);
|
||||
unset($_SERVER['HTTPS_PROXY']);
|
||||
unset($_SERVER['https_proxy']);
|
||||
unset($_SERVER['no_proxy']);
|
||||
}
|
||||
|
||||
|
@ -27,6 +29,8 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
unset($_SERVER['HTTP_PROXY']);
|
||||
unset($_SERVER['http_proxy']);
|
||||
unset($_SERVER['HTTPS_PROXY']);
|
||||
unset($_SERVER['https_proxy']);
|
||||
unset($_SERVER['no_proxy']);
|
||||
}
|
||||
|
||||
|
@ -126,17 +130,56 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$_SERVER['http_proxy'] = 'http://username:password@proxyserver.net';
|
||||
|
||||
$context = StreamContextFactory::getContext('http://example.org', array('http' => array('method' => 'GET')));
|
||||
$context = StreamContextFactory::getContext('https://example.org', array('http' => array('method' => 'GET')));
|
||||
$options = stream_context_get_options($context);
|
||||
|
||||
$this->assertEquals(array('http' => array(
|
||||
$expected = array(
|
||||
'http' => array(
|
||||
'proxy' => 'tcp://proxyserver.net:80',
|
||||
'request_fulluri' => true,
|
||||
'method' => 'GET',
|
||||
'header' => array("Proxy-Authorization: Basic " . base64_encode('username:password')),
|
||||
'max_redirects' => 20,
|
||||
'follow_location' => 1,
|
||||
)), $options);
|
||||
), 'ssl' => array(
|
||||
'SNI_enabled' => true,
|
||||
'SNI_server_name' => 'example.org'
|
||||
)
|
||||
);
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
|
||||
unset($expected['ssl']['SNI_server_name']);
|
||||
}
|
||||
$this->assertEquals($expected, $options);
|
||||
}
|
||||
|
||||
public function testHttpsProxyOverride()
|
||||
{
|
||||
if (!extension_loaded('openssl')) {
|
||||
$this->markTestSkipped('Requires openssl');
|
||||
}
|
||||
|
||||
$_SERVER['http_proxy'] = 'http://username:password@proxyserver.net';
|
||||
$_SERVER['https_proxy'] = 'https://woopproxy.net';
|
||||
|
||||
$context = StreamContextFactory::getContext('https://example.org', array('http' => array('method' => 'GET')));
|
||||
$options = stream_context_get_options($context);
|
||||
|
||||
$expected = array(
|
||||
'http' => array(
|
||||
'proxy' => 'ssl://woopproxy.net:443',
|
||||
'request_fulluri' => true,
|
||||
'method' => 'GET',
|
||||
'max_redirects' => 20,
|
||||
'follow_location' => 1,
|
||||
), 'ssl' => array(
|
||||
'SNI_enabled' => true,
|
||||
'SNI_server_name' => 'example.org'
|
||||
)
|
||||
);
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
|
||||
unset($expected['ssl']['SNI_server_name']);
|
||||
}
|
||||
$this->assertEquals($expected, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue