Merge remote-tracking branch 'upstream/master' into svn-auth-reloaded
commit
8f96786693
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
* Added `create-project` command to install a project from scratch with composer
|
* Added `create-project` command to install a project from scratch with composer
|
||||||
* Added automated `classmap` autoloading support for non-PSR-0 compliant projects
|
* Added automated `classmap` autoloading support for non-PSR-0 compliant projects
|
||||||
* Git clones from GitHub automatically select between git/https/http protocols
|
* Improved clones from GitHub which now automatically select between git/https/http protocols
|
||||||
* Enhanced `validate` command to give more feedback
|
* Added support for private GitHub repositories (use --no-interaction for CI)
|
||||||
|
* Improved `validate` command to give more feedback
|
||||||
* Added "file" downloader type to download plain files
|
* Added "file" downloader type to download plain files
|
||||||
* Added support for authentication with svn repositories
|
* Added support for authentication with svn repositories
|
||||||
* Dependency on filter_var is now optional
|
* Removed dependency on filter_var
|
||||||
* Various robustness & error handling improvements
|
* Improved the `search` & `show` commands output
|
||||||
|
* Various robustness & error handling improvements, docs fixes and more
|
||||||
|
|
||||||
* 1.0.0-alpha1 (2012-03-01)
|
* 1.0.0-alpha1 (2012-03-01)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
if ((!@include __DIR__.'/../../../.composer/autoload.php') && (!@include __DIR__.'/../vendor/.composer/autoload.php')) {
|
require __DIR__.'/../src/bootstrap.php';
|
||||||
die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
|
|
||||||
'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
|
|
||||||
'php composer.phar install'.PHP_EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
use Composer\Compiler;
|
use Composer\Compiler;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
if ((!@include __DIR__.'/../../../.composer/autoload.php') && (!@include __DIR__.'/../vendor/.composer/autoload.php')) {
|
require __DIR__.'/../src/bootstrap.php';
|
||||||
die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
|
|
||||||
'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
|
|
||||||
'php composer.phar install'.PHP_EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
use Composer\Console\Application;
|
use Composer\Console\Application;
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,10 @@
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "Composer": "src/" }
|
"psr-0": { "Composer": "src/" }
|
||||||
},
|
},
|
||||||
"bin": ["bin/composer"]
|
"bin": ["bin/composer"],
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"hash": "959be339ea6f0b140f09215c4ef451cc",
|
"hash": "df0b80bd7287f1783e3bf2a2c4b9db63",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"package": "justinrainbow/json-schema",
|
"package": "justinrainbow/json-schema",
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
{
|
{
|
||||||
"package": "seld/jsonlint",
|
"package": "seld/jsonlint",
|
||||||
"version": "dev-master",
|
"version": "dev-master",
|
||||||
"source-reference": "12f0b1e5334a52b7035e1d15f36974db7c06b78d"
|
"source-reference": "869e5d011fe1c82501ae0a3b427a686c21fd5baf"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package": "symfony/console",
|
"package": "symfony/console",
|
||||||
|
|
|
@ -1,23 +1,30 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Composer is a tool for dependency management in PHP. It allows you to declare
|
Composer is a tool for dependency management in PHP. It allows you to declare
|
||||||
the dependencies of your project and will install them for you.
|
the dependent libraries your project needs and it will install them in your
|
||||||
|
project for you.
|
||||||
|
|
||||||
## Dependency management
|
## Dependency management
|
||||||
|
|
||||||
One important distinction to make is that composer is not a package manager. It
|
Composer is not a package manager. Yes, it deals with "packages" or libraries, but
|
||||||
deals with packages, but it manages them on a per-project basis. By default it
|
it manages them on a per-project basis, installing them in a directory (e.g. `vendor`)
|
||||||
will never install anything globally. Thus, it is a dependency manager.
|
inside your project. By default it will never install anything globally. Thus,
|
||||||
|
it is a dependency manager.
|
||||||
|
|
||||||
This idea is not new by any means. Composer is strongly inspired by
|
This idea is not new and Composer is strongly inspired by node's [npm](http://npmjs.org/)
|
||||||
node's [npm](http://npmjs.org/) and ruby's [bundler](http://gembundler.com/).
|
and ruby's [bundler](http://gembundler.com/). But there has not been such a tool
|
||||||
But there has not been such a tool for PHP so far.
|
for PHP.
|
||||||
|
|
||||||
The problem that composer solves is the following. You have a project that
|
The problem that Composer solves is this:
|
||||||
depends on a number of libraries. Some of those libraries have dependencies of
|
|
||||||
their own. You declare the things you depend on. Composer will then go ahead
|
a) You have a project that depends on a number of libraries.
|
||||||
and find out which versions of which packages need to be installed, and
|
|
||||||
install them.
|
b) Some of those libraries depend on other libraries .
|
||||||
|
|
||||||
|
c) You declare the things you depend on
|
||||||
|
|
||||||
|
d) Composer finds out which versions of which packages need to be installed, and
|
||||||
|
installs them (meaning it downloads them into your project).
|
||||||
|
|
||||||
## Declaring dependencies
|
## Declaring dependencies
|
||||||
|
|
||||||
|
@ -32,37 +39,50 @@ which describes the project's dependencies.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
We are simply stating that our project requires the `monolog/monolog` package,
|
We are simply stating that our project requires some `monolog/monolog` package,
|
||||||
any version beginning with `1.0`.
|
any version beginning with `1.0`.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To actually get it, we need to do two things. The first one is installing
|
### 1) Downloading the Composer Executable
|
||||||
composer:
|
|
||||||
|
To actually get Composer, we need to do two things. The first one is installing
|
||||||
|
Composer (again, this mean downloading it into your project):
|
||||||
|
|
||||||
$ curl -s http://getcomposer.org/installer | php
|
$ curl -s http://getcomposer.org/installer | php
|
||||||
|
|
||||||
This will just check a few PHP settings and then download `composer.phar` to
|
This will just check a few PHP settings and then download `composer.phar` to
|
||||||
your working directory. This file is the composer binary.
|
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.
|
||||||
|
|
||||||
You can install composer to a specific directory by using the `--install-dir`
|
You can install Composer to a specific directory by using the `--install-dir`
|
||||||
option and providing a target directory (it can be an absolute or relative path):
|
option and providing a target directory (it can be an absolute or relative path):
|
||||||
|
|
||||||
$ curl -s http://getcomposer.org/installer | php -- --install-dir=bin
|
$ curl -s http://getcomposer.org/installer | php -- --install-dir=bin
|
||||||
|
|
||||||
After that we run the command for installing all dependencies:
|
You can place this file anywhere you wish. If you put it in your `PATH`,
|
||||||
|
you can access it globally. On unixy systems you can even make it
|
||||||
|
executable and invoke it without `php`.
|
||||||
|
|
||||||
|
### 2) Using Composer
|
||||||
|
|
||||||
|
Next, run the command the `install` command to resolve and download dependencies:
|
||||||
|
|
||||||
$ php composer.phar install
|
$ php composer.phar install
|
||||||
|
|
||||||
This will download monolog and dump it into `vendor/monolog/monolog`.
|
This will download monolog into the `vendor/monolog/monolog` directory.
|
||||||
|
|
||||||
## Autoloading
|
## Autoloading
|
||||||
|
|
||||||
After this you can just add the following line to your bootstrap code to get
|
Besides downloading the library, Composer also prepares an autoload file that's
|
||||||
autoloading:
|
capable of autoloading all of the classes in any of the libraries that it
|
||||||
|
downloads. To use it, just add the following line to your code's bootstrap
|
||||||
|
process:
|
||||||
|
|
||||||
require 'vendor/.composer/autoload.php';
|
require 'vendor/.composer/autoload.php';
|
||||||
|
|
||||||
That's all it takes to have a basic setup.
|
Woh! Now start using monolog! To keep learning more about Composer, keep
|
||||||
|
reading the "Basic Usage" chapter.
|
||||||
|
|
||||||
[Basic Usage](01-basic-usage.md) →
|
[Basic Usage](01-basic-usage.md) →
|
||||||
|
|
|
@ -2,49 +2,36 @@
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install composer, simply run this command on the command line:
|
To install Composer, you just need to download the `composer.phar` executable.
|
||||||
|
|
||||||
$ curl -s http://getcomposer.org/installer | php
|
$ curl -s http://getcomposer.org/installer | php
|
||||||
|
|
||||||
This will perform some checks on your environment to make sure you can
|
For the details, see the [Introduction](00-intro.md) chapter.
|
||||||
actually run it.
|
|
||||||
|
|
||||||
Then it will download `composer.phar` and place it in your working directory.
|
To check if Composer is working, just run the PHAR through `php`:
|
||||||
`composer.phar` 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.
|
|
||||||
|
|
||||||
You can place this file anywhere you wish. If you put it in your `PATH`,
|
|
||||||
you can access it globally. On unixy systems you can even make it
|
|
||||||
executable and invoke it without `php`.
|
|
||||||
|
|
||||||
You can install composer to a specific directory by using the `--install-dir`
|
|
||||||
option and providing a target directory (it can be an absolute or relative path):
|
|
||||||
|
|
||||||
$ curl -s http://getcomposer.org/installer | php -- --install-dir=bin
|
|
||||||
|
|
||||||
To check if composer is working, just run the PHAR through `php`:
|
|
||||||
|
|
||||||
$ php composer.phar
|
$ php composer.phar
|
||||||
|
|
||||||
This should give you a list of available commands.
|
This should give you a list of available commands.
|
||||||
|
|
||||||
> **Note:** You can also perform the checks only without downloading composer
|
> **Note:** You can also perform the checks only without downloading Composer
|
||||||
> by using the `--check` option. For more information, just use `--help`.
|
> by using the `--check` option. For more information, just use `--help`.
|
||||||
>
|
>
|
||||||
> $ curl -s http://getcomposer.org/installer | php -- --help
|
> $ curl -s http://getcomposer.org/installer | php -- --help
|
||||||
|
|
||||||
## Project setup
|
## `composer.json`: Project Setup
|
||||||
|
|
||||||
To start using composer in your project, all you need is a `composer.json`
|
To start using Composer in your project, all you need is a `composer.json`
|
||||||
file. This file describes the dependencies of your project and may contain
|
file. This file describes the dependencies of your project and may contain
|
||||||
other metadata as well.
|
other metadata as well.
|
||||||
|
|
||||||
The [JSON format](http://json.org/) is quite easy to write. It allows you to
|
The [JSON format](http://json.org/) is quite easy to write. It allows you to
|
||||||
define nested structures.
|
define nested structures.
|
||||||
|
|
||||||
|
### The `require` Key
|
||||||
|
|
||||||
The first (and often only) thing you specify in `composer.json` is the
|
The first (and often only) thing you specify in `composer.json` is the
|
||||||
`require` key. You're simply telling composer which packages your project
|
`require` key. You're simply telling Composer which packages your project
|
||||||
depends on.
|
depends on.
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -53,12 +40,13 @@ depends on.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
As you can see, `require` takes an object that maps package names to versions.
|
As you can see, `require` takes an object that maps **package names** (e.g. `monolog/monolog`)
|
||||||
|
to **package versions** (e.g. `1.0.*`).
|
||||||
|
|
||||||
## Package names
|
### Package Names
|
||||||
|
|
||||||
The package name consists of a vendor name and the project's name. Often these
|
The package name consists of a vendor name and the project's name. Often these
|
||||||
will be identical. The vendor name exists to prevent naming clashes. It allows
|
will be identical - the vendor name just exists to prevent naming clashes. It allows
|
||||||
two different people to create a library named `json`, which would then just be
|
two different people to create a library named `json`, which would then just be
|
||||||
named `igorw/json` and `seldaek/json`.
|
named `igorw/json` and `seldaek/json`.
|
||||||
|
|
||||||
|
@ -68,10 +56,10 @@ allows adding more related projects under the same namespace later on. If you
|
||||||
are maintaining a library, this would make it really easy to split it up into
|
are maintaining a library, this would make it really easy to split it up into
|
||||||
smaller decoupled parts.
|
smaller decoupled parts.
|
||||||
|
|
||||||
## Package versions
|
### Package Versions
|
||||||
|
|
||||||
We are also requiring the version `1.0.*` of monolog. This means any version
|
We are requiring version `1.0.*` of monolog. This means any version in the `1.0`
|
||||||
in the `1.0` development branch. It would match `1.0.0`, `1.0.2` and `1.0.20`.
|
development branch. It would match `1.0.0`, `1.0.2` or `1.0.20`.
|
||||||
|
|
||||||
Version constraints can be specified in a few different ways.
|
Version constraints can be specified in a few different ways.
|
||||||
|
|
||||||
|
@ -80,14 +68,14 @@ Version constraints can be specified in a few different ways.
|
||||||
|
|
||||||
* **Range:** By using comparison operators you can specify ranges of valid
|
* **Range:** By using comparison operators you can specify ranges of valid
|
||||||
versions. Valid operators are `>`, `>=`, `<`, `<=`. An example range would be
|
versions. Valid operators are `>`, `>=`, `<`, `<=`. An example range would be
|
||||||
`>=1.0`. You can define multiple of these, separated by comma: `>=1.0,<2.0`.
|
`>=1.0`. You can define multiple ranges, separated by a comma: `>=1.0,<2.0`.
|
||||||
|
|
||||||
* **Wildcard:** You can specify a pattern with a `*` wildcard. `1.0.*` is the
|
* **Wildcard:** You can specify a pattern with a `*` wildcard. `1.0.*` is the
|
||||||
equivalent of `>=1.0,<1.1-dev`.
|
equivalent of `>=1.0,<1.1-dev`.
|
||||||
|
|
||||||
## Installing dependencies
|
## Installing Dependencies
|
||||||
|
|
||||||
To fetch the defined dependencies into the local project, you simply run the
|
To fetch the defined dependencies into your local project, just run the
|
||||||
`install` command of `composer.phar`.
|
`install` command of `composer.phar`.
|
||||||
|
|
||||||
$ php composer.phar install
|
$ php composer.phar install
|
||||||
|
@ -104,29 +92,33 @@ In case of monolog it will put it into `vendor/monolog/monolog`.
|
||||||
Another thing that the `install` command does is it adds a `composer.lock`
|
Another thing that the `install` command does is it adds a `composer.lock`
|
||||||
file into your project root.
|
file into your project root.
|
||||||
|
|
||||||
## Lock file
|
## `composer.lock` - The Lock File
|
||||||
|
|
||||||
After installing the dependencies, composer writes the list of the exact
|
After installing the dependencies, Composer writes the list of the exact
|
||||||
versions it installed into a `composer.lock` file. This locks the project
|
versions it installed into a `composer.lock` file. This locks the project
|
||||||
to those specific versions.
|
to those specific versions.
|
||||||
|
|
||||||
**Commit your project's `composer.lock` into version control.**
|
**Commit your project's `composer.lock` (along with `composer.json`) into version control.**
|
||||||
|
|
||||||
The reason is that anyone who sets up the project should get the same version.
|
This is important because the `install` command checks if a lock file is present,
|
||||||
The `install` command will check if a lock file is present. If it is, it will
|
and if it is, it downloads the versions specified there (regardless of what `composer.json`
|
||||||
use the versions specified there. If not, it will resolve the dependencies and
|
says). This means that anyone who sets up the project will download the exact
|
||||||
create a lock file.
|
same version of the dependencies.
|
||||||
|
|
||||||
If any of the dependencies gets a new version, you can update to that version
|
If no `composer.json` lock file exists, it will read the dependencies and
|
||||||
by using the `update` command. This will fetch the latest matching versions and
|
versions from `composer.json` and create the lock file.
|
||||||
also update the lock file.
|
|
||||||
|
This means that if any of the dependencies get a new version, you won't get the updates.
|
||||||
|
automatically. To update to the new version, use `update` command. This will fetch
|
||||||
|
the latest matching versions (according to your `composer.json` file) and also update
|
||||||
|
the lock file with the new version.
|
||||||
|
|
||||||
$ php composer.phar update
|
$ php composer.phar update
|
||||||
|
|
||||||
## Packagist
|
## Packagist
|
||||||
|
|
||||||
[Packagist](http://packagist.org/) is the main composer repository. A composer
|
[Packagist](http://packagist.org/) is the main Composer repository. A Composer
|
||||||
repository is basically a package source. A place where you can get packages
|
repository is basically a package source: a place where you can get packages
|
||||||
from. Packagist aims to be the central repository that everybody uses. This
|
from. Packagist aims to be the central repository that everybody uses. This
|
||||||
means that you can automatically `require` any package that is available
|
means that you can automatically `require` any package that is available
|
||||||
there.
|
there.
|
||||||
|
@ -134,20 +126,20 @@ there.
|
||||||
If you go to the [packagist website](http://packagist.org/) (packagist.org),
|
If you go to the [packagist website](http://packagist.org/) (packagist.org),
|
||||||
you can browse and search for packages.
|
you can browse and search for packages.
|
||||||
|
|
||||||
Any open source project using composer should publish their packages on
|
Any open source project using Composer should publish their packages on
|
||||||
packagist.
|
packagist. A library doesn't need to be on packagist to be used by Composer,
|
||||||
|
but it makes life quite a bit simpler.
|
||||||
|
|
||||||
## Autoloading
|
## Autoloading
|
||||||
|
|
||||||
For libraries that follow the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
|
For libraries that follow the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
|
||||||
naming standard, composer generates a
|
naming standard, Composer generates a `vendor/.composer/autoload.php` file
|
||||||
`vendor/.composer/autoload.php` file for autoloading. You can simply include
|
for autoloading. You can simply include this file and you will get autoloading
|
||||||
this file and you will get autoloading for free.
|
for free.
|
||||||
|
|
||||||
require 'vendor/.composer/autoload.php';
|
require 'vendor/.composer/autoload.php';
|
||||||
|
|
||||||
This makes it really easy to use third party code, because you only
|
This makes it really easy to use third party code: For monolog, it
|
||||||
have to add one line to `composer.json` and run `install`. For monolog, it
|
|
||||||
means that we can just start using classes from it, and they will be
|
means that we can just start using classes from it, and they will be
|
||||||
autoloaded.
|
autoloaded.
|
||||||
|
|
||||||
|
|
|
@ -96,9 +96,9 @@ example we will publish the `acme/hello-world` library on GitHub under
|
||||||
`github.com/composer/hello-world`.
|
`github.com/composer/hello-world`.
|
||||||
|
|
||||||
Now, To test installing the `acme/hello-world` package, we create a new
|
Now, To test installing the `acme/hello-world` package, we create a new
|
||||||
project locally. We will call it `acme/blog`. This blog will depend on `acme
|
project locally. We will call it `acme/blog`. This blog will depend on
|
||||||
/hello-world`, which in turn depends on `monolog/monolog`. We can accomplish
|
`acme/hello-world`, which in turn depends on `monolog/monolog`. We can
|
||||||
this by creating a new `blog` directory somewhere, containing a
|
accomplish this by creating a new `blog` directory somewhere, containing a
|
||||||
`composer.json`:
|
`composer.json`:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -157,7 +157,7 @@ will always take precedence over the values specified in `composer.json`.
|
||||||
|
|
||||||
### COMPOSER
|
### COMPOSER
|
||||||
|
|
||||||
By setting the `COMPOSER` env variable is is possible to set the filename of
|
By setting the `COMPOSER` env variable it is possible to set the filename of
|
||||||
`composer.json` to something else.
|
`composer.json` to something else.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
|
@ -13,7 +13,9 @@ can also be used to validate your `composer.json`. In fact, it is used by the
|
||||||
|
|
||||||
The root of the package definition is a JSON object.
|
The root of the package definition is a JSON object.
|
||||||
|
|
||||||
## name
|
## Properties
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
The name of the package. It consists of vendor name and project name,
|
The name of the package. It consists of vendor name and project name,
|
||||||
separated by `/`.
|
separated by `/`.
|
||||||
|
@ -25,13 +27,13 @@ Examples:
|
||||||
|
|
||||||
Required for published packages (libraries).
|
Required for published packages (libraries).
|
||||||
|
|
||||||
## description
|
### description
|
||||||
|
|
||||||
A short description of the package. Usually this is just one line long.
|
A short description of the package. Usually this is just one line long.
|
||||||
|
|
||||||
Optional but recommended.
|
Optional but recommended.
|
||||||
|
|
||||||
## version
|
### version
|
||||||
|
|
||||||
The version of the package.
|
The version of the package.
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ Optional if the package repository can infer the version from somewhere, such
|
||||||
as the VCS tag name in the VCS repository. In that case it is also recommended
|
as the VCS tag name in the VCS repository. In that case it is also recommended
|
||||||
to omit it.
|
to omit it.
|
||||||
|
|
||||||
## type
|
### type
|
||||||
|
|
||||||
The type of the package. It defaults to `library`.
|
The type of the package. It defaults to `library`.
|
||||||
|
|
||||||
|
@ -74,7 +76,7 @@ order to be able to install the bundle.
|
||||||
Only use a custom type if you need custom logic during installation. It is
|
Only use a custom type if you need custom logic during installation. It is
|
||||||
recommended to omit this field and have it just default to `library`.
|
recommended to omit this field and have it just default to `library`.
|
||||||
|
|
||||||
## keywords
|
### keywords
|
||||||
|
|
||||||
An array of keywords that the package is related to. These can be used for
|
An array of keywords that the package is related to. These can be used for
|
||||||
searching and filtering.
|
searching and filtering.
|
||||||
|
@ -89,13 +91,13 @@ Examples:
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## homepage
|
### homepage
|
||||||
|
|
||||||
An URL to the website of the project.
|
An URL to the website of the project.
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## time
|
### time
|
||||||
|
|
||||||
Release date of the version.
|
Release date of the version.
|
||||||
|
|
||||||
|
@ -103,7 +105,7 @@ Must be in `YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS` format.
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## license
|
### license
|
||||||
|
|
||||||
The license of the package. This can be either a string or an array of strings.
|
The license of the package. This can be either a string or an array of strings.
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ The recommended notation for the most common licenses is:
|
||||||
|
|
||||||
Optional, but it is highly recommended to supply this.
|
Optional, but it is highly recommended to supply this.
|
||||||
|
|
||||||
## authors
|
### authors
|
||||||
|
|
||||||
The authors of the package. This is an array of objects.
|
The authors of the package. This is an array of objects.
|
||||||
|
|
||||||
|
@ -151,7 +153,7 @@ An example:
|
||||||
|
|
||||||
Optional, but highly recommended.
|
Optional, but highly recommended.
|
||||||
|
|
||||||
## Link types
|
### Link types
|
||||||
|
|
||||||
Each of these takes an object which maps package names to version constraints.
|
Each of these takes an object which maps package names to version constraints.
|
||||||
|
|
||||||
|
@ -179,7 +181,7 @@ Example:
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## autoload
|
### autoload
|
||||||
|
|
||||||
Autoload mapping for a PHP autoloader.
|
Autoload mapping for a PHP autoloader.
|
||||||
|
|
||||||
|
@ -211,7 +213,7 @@ Example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## target-dir
|
### target-dir
|
||||||
|
|
||||||
Defines the installation target.
|
Defines the installation target.
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ To do that, `autoload` and `target-dir` are defined as follows:
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## repositories
|
### repositories
|
||||||
|
|
||||||
Custom package repositories to use.
|
Custom package repositories to use.
|
||||||
|
|
||||||
|
@ -297,11 +299,12 @@ Example:
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
> **Note:** Order is significant here. Repositories added later will take
|
> **Note:** Order is significant here. When looking for a package, Composer
|
||||||
precedence. This also means that custom repositories can override packages
|
will look from the first to the last repository, and pick the first match.
|
||||||
that exist on packagist.
|
By default Packagist is added last which means that custom repositories can
|
||||||
|
override packages from it.
|
||||||
|
|
||||||
## config
|
### config
|
||||||
|
|
||||||
A set of configuration options. It is only used for projects.
|
A set of configuration options. It is only used for projects.
|
||||||
|
|
||||||
|
@ -323,7 +326,7 @@ Example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## scripts
|
### scripts
|
||||||
|
|
||||||
Composer allows you to hook into various parts of the installation process
|
Composer allows you to hook into various parts of the installation process
|
||||||
through the use of scripts.
|
through the use of scripts.
|
||||||
|
@ -382,7 +385,7 @@ which gives you access to the `Composer\Composer` instance through the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## extra
|
### extra
|
||||||
|
|
||||||
Arbitrary extra data for consumption by `scripts`.
|
Arbitrary extra data for consumption by `scripts`.
|
||||||
|
|
||||||
|
@ -393,12 +396,12 @@ handler, you can do:
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
## bin
|
### bin
|
||||||
|
|
||||||
A set of files that should be treated as binaries and symlinked into the `bin-
|
A set of files that should be treated as binaries and symlinked into the `bin-
|
||||||
dir` (from config).
|
dir` (from config).
|
||||||
|
|
||||||
See (Vendor Bins)[articles/vendor-bins.md] for more details.
|
See [Vendor Bins](articles/vendor-bins.md) for more details.
|
||||||
|
|
||||||
Optional.
|
Optional.
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Composer\Json\JsonFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install a package as new project into new directory.
|
* Install a package as new project into new directory.
|
||||||
|
@ -85,7 +86,7 @@ EOT
|
||||||
if (null === $repositoryUrl) {
|
if (null === $repositoryUrl) {
|
||||||
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'));
|
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'));
|
||||||
} elseif (".json" === substr($repositoryUrl, -5)) {
|
} elseif (".json" === substr($repositoryUrl, -5)) {
|
||||||
$sourceRepo = new FilesystemRepository($repositoryUrl);
|
$sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl));
|
||||||
} elseif (0 === strpos($repositoryUrl, 'http')) {
|
} elseif (0 === strpos($repositoryUrl, 'http')) {
|
||||||
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl));
|
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -33,7 +33,7 @@ class InitCommand extends Command
|
||||||
|
|
||||||
public function parseAuthorString($author)
|
public function parseAuthorString($author)
|
||||||
{
|
{
|
||||||
if (preg_match('/^(?P<name>[- \.,a-z0-9]+) <(?P<email>.+?)>$/i', $author, $match)) {
|
if (preg_match('/^(?P<name>[- \.,\w]+) <(?P<email>.+?)>$/u', $author, $match)) {
|
||||||
if (!function_exists('filter_var') || $match['email'] === filter_var($match['email'], FILTER_VALIDATE_EMAIL)) {
|
if (!function_exists('filter_var') || $match['email'] === filter_var($match['email'], FILTER_VALIDATE_EMAIL)) {
|
||||||
return array(
|
return array(
|
||||||
'name' => trim($match['name']),
|
'name' => trim($match['name']),
|
||||||
|
|
|
@ -102,12 +102,11 @@ class Compiler
|
||||||
{
|
{
|
||||||
$path = str_replace(dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR, '', $file->getRealPath());
|
$path = str_replace(dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR, '', $file->getRealPath());
|
||||||
|
|
||||||
if ($strip) {
|
|
||||||
$content = php_strip_whitespace($file);
|
|
||||||
} elseif ('LICENSE' === basename($file)) {
|
|
||||||
$content = "\n".file_get_contents($file)."\n";
|
|
||||||
} else {
|
|
||||||
$content = file_get_contents($file);
|
$content = file_get_contents($file);
|
||||||
|
if ($strip) {
|
||||||
|
$content = $this->stripWhitespace($content);
|
||||||
|
} elseif ('LICENSE' === basename($file)) {
|
||||||
|
$content = "\n".$content."\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = str_replace('@package_version@', $this->version, $content);
|
$content = str_replace('@package_version@', $this->version, $content);
|
||||||
|
@ -122,6 +121,40 @@ class Compiler
|
||||||
$phar->addFromString('bin/composer', $content);
|
$phar->addFromString('bin/composer', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes whitespace from a PHP source string while preserving line numbers.
|
||||||
|
*
|
||||||
|
* @param string $source A PHP string
|
||||||
|
* @return string The PHP string with the whitespace removed
|
||||||
|
*/
|
||||||
|
private function stripWhitespace($source)
|
||||||
|
{
|
||||||
|
if (!function_exists('token_get_all')) {
|
||||||
|
return $source;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
foreach (token_get_all($source) as $token) {
|
||||||
|
if (is_string($token)) {
|
||||||
|
$output .= $token;
|
||||||
|
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
|
||||||
|
$output .= str_repeat("\n", substr_count($token[1], "\n"));
|
||||||
|
} elseif (T_WHITESPACE === $token[0]) {
|
||||||
|
// reduce wide spaces
|
||||||
|
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
|
||||||
|
// normalize newlines to \n
|
||||||
|
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
|
||||||
|
// trim leading spaces
|
||||||
|
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
|
||||||
|
$output .= $whitespace;
|
||||||
|
} else {
|
||||||
|
$output .= $token[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
private function getStub()
|
private function getStub()
|
||||||
{
|
{
|
||||||
return <<<'EOF'
|
return <<<'EOF'
|
||||||
|
|
|
@ -53,7 +53,7 @@ class Pool
|
||||||
throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
|
throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $priority;
|
return -$priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -911,7 +911,7 @@ class Solver
|
||||||
$this->installedMap[$package->getId()] = $package;
|
$this->installedMap[$package->getId()] = $package;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5.3.3', '>')) {
|
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||||
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
|
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
|
||||||
} else {
|
} else {
|
||||||
$this->decisionMap = array_fill(0, $this->pool->getMaxId() + 1, 0);
|
$this->decisionMap = array_fill(0, $this->pool->getMaxId() + 1, 0);
|
||||||
|
|
|
@ -15,7 +15,6 @@ namespace Composer\Downloader;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Util\RemoteFilesystem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base downloader for archives
|
* Base downloader for archives
|
||||||
|
|
|
@ -27,15 +27,17 @@ use Composer\Util\RemoteFilesystem;
|
||||||
class FileDownloader implements DownloaderInterface
|
class FileDownloader implements DownloaderInterface
|
||||||
{
|
{
|
||||||
protected $io;
|
protected $io;
|
||||||
|
protected $rfs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param IOInterface $io The IO instance
|
* @param IOInterface $io The IO instance
|
||||||
*/
|
*/
|
||||||
public function __construct(IOInterface $io)
|
public function __construct(IOInterface $io, RemoteFilesystem $rfs = null)
|
||||||
{
|
{
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
|
$this->rfs = $rfs ?: new RemoteFilesystem($io);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,8 +73,7 @@ class FileDownloader implements DownloaderInterface
|
||||||
|
|
||||||
$url = $this->processUrl($url);
|
$url = $this->processUrl($url);
|
||||||
|
|
||||||
$rfs = new RemoteFilesystem($this->io);
|
$this->rfs->copy($package->getSourceUrl(), $url, $fileName);
|
||||||
$rfs->copy($package->getSourceUrl(), $url, $fileName);
|
|
||||||
$this->io->write('');
|
$this->io->write('');
|
||||||
|
|
||||||
if (!file_exists($fileName)) {
|
if (!file_exists($fileName)) {
|
||||||
|
|
|
@ -34,6 +34,13 @@ class GitDownloader extends VcsDownloader
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->runCommand($commandCallable, $package->getSourceUrl(), $path);
|
$this->runCommand($commandCallable, $package->getSourceUrl(), $path);
|
||||||
|
|
||||||
|
// set push url for github projects
|
||||||
|
if (preg_match('{^(?:https?|git)://github.com/([^/]+)/([^/]+?)(?:\.git)?$}', $package->getSourceUrl(), $match)) {
|
||||||
|
$pushUrl = 'git@github.com:'.$match[1].'/'.$match[2].'.git';
|
||||||
|
$cmd = sprintf('cd %s && git remote set-url --push origin %s', escapeshellarg($path), escapeshellarg($pushUrl));
|
||||||
|
$this->process->execute($cmd, $ignoredOutput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,17 +78,7 @@ class Factory
|
||||||
$rm = $this->createRepositoryManager($io);
|
$rm = $this->createRepositoryManager($io);
|
||||||
|
|
||||||
// load default repository unless it's explicitly disabled
|
// load default repository unless it's explicitly disabled
|
||||||
$loadPackagist = true;
|
$packageConfig = $this->addPackagistRepository($packageConfig);
|
||||||
if (isset($packageConfig['repositories'])) {
|
|
||||||
foreach ($packageConfig['repositories'] as $repo) {
|
|
||||||
if (isset($repo['packagist']) && $repo['packagist'] === false) {
|
|
||||||
$loadPackagist = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($loadPackagist) {
|
|
||||||
$this->addPackagistRepository($rm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load local repository
|
// load local repository
|
||||||
$this->addLocalRepository($rm, $vendorDir);
|
$this->addLocalRepository($rm, $vendorDir);
|
||||||
|
@ -103,6 +93,9 @@ class Factory
|
||||||
// initialize installation manager
|
// initialize installation manager
|
||||||
$im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io);
|
$im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io);
|
||||||
|
|
||||||
|
// purge packages if they have been deleted on the filesystem
|
||||||
|
$this->purgePackages($rm, $im);
|
||||||
|
|
||||||
// init locker
|
// init locker
|
||||||
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
|
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
|
||||||
$locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
|
$locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
|
||||||
|
@ -137,9 +130,33 @@ class Factory
|
||||||
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
|
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addPackagistRepository(RepositoryManager $rm)
|
protected function addPackagistRepository(array $packageConfig)
|
||||||
{
|
{
|
||||||
$rm->addRepository(new Repository\ComposerRepository(array('url' => 'http://packagist.org')));
|
$loadPackagist = true;
|
||||||
|
$packagistConfig = array(
|
||||||
|
'type' => 'composer',
|
||||||
|
'url' => 'http://packagist.org'
|
||||||
|
);
|
||||||
|
if (isset($packageConfig['repositories'])) {
|
||||||
|
foreach ($packageConfig['repositories'] as $key => $repo) {
|
||||||
|
if (isset($repo['packagist'])) {
|
||||||
|
if (true === $repo['packagist']) {
|
||||||
|
$packageConfig['repositories'][$key] = $packagistConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
$loadPackagist = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$packageConfig['repositories'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($loadPackagist) {
|
||||||
|
$packageConfig['repositories'][] = $packagistConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packageConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createDownloadManager(IOInterface $io)
|
public function createDownloadManager(IOInterface $io)
|
||||||
|
@ -166,6 +183,15 @@ class Factory
|
||||||
return $im;
|
return $im;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im)
|
||||||
|
{
|
||||||
|
foreach ($rm->getLocalRepository()->getPackages() as $package) {
|
||||||
|
if (!$im->isPackageInstalled($package)) {
|
||||||
|
$rm->getLocalRepository()->removePackage($package);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static public function create(IOInterface $io, $composerFile = null)
|
static public function create(IOInterface $io, $composerFile = null)
|
||||||
{
|
{
|
||||||
$factory = new static();
|
$factory = new static();
|
||||||
|
|
|
@ -68,7 +68,7 @@ class RootPackageLoader extends ArrayLoader
|
||||||
throw new \UnexpectedValueException('Repository '.$index.' should be an array, '.gettype($repo).' given');
|
throw new \UnexpectedValueException('Repository '.$index.' should be an array, '.gettype($repo).' given');
|
||||||
}
|
}
|
||||||
if (!isset($repo['type'])) {
|
if (!isset($repo['type'])) {
|
||||||
throw new \UnexpectedValueException('Repository '.$index.' must have a type defined');
|
throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined');
|
||||||
}
|
}
|
||||||
$repository = $this->manager->createRepository($repo['type'], $repo);
|
$repository = $this->manager->createRepository($repo['type'], $repo);
|
||||||
$this->manager->addRepository($repository);
|
$this->manager->addRepository($repository);
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
namespace Composer\Repository\Vcs;
|
namespace Composer\Repository\Vcs;
|
||||||
|
|
||||||
|
use Composer\Downloader\TransportException;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Util\ProcessExecutor;
|
||||||
|
use Composer\Util\RemoteFilesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
@ -16,14 +19,30 @@ class GitHubDriver extends VcsDriver
|
||||||
protected $branches;
|
protected $branches;
|
||||||
protected $rootIdentifier;
|
protected $rootIdentifier;
|
||||||
protected $infoCache = array();
|
protected $infoCache = array();
|
||||||
|
protected $isPrivate = false;
|
||||||
|
|
||||||
public function __construct($url, IOInterface $io)
|
/**
|
||||||
|
* Git Driver
|
||||||
|
*
|
||||||
|
* @var GitDriver
|
||||||
|
*/
|
||||||
|
protected $gitDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param IOInterface $io
|
||||||
|
* @param ProcessExecutor $process
|
||||||
|
* @param RemoteFilesystem $remoteFilesystem
|
||||||
|
*/
|
||||||
|
public function __construct($url, IOInterface $io, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
|
||||||
{
|
{
|
||||||
preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match);
|
preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match);
|
||||||
$this->owner = $match[1];
|
$this->owner = $match[1];
|
||||||
$this->repository = $match[2];
|
$this->repository = $match[2];
|
||||||
|
|
||||||
parent::__construct($url, $io);
|
parent::__construct($url, $io, $process, $remoteFilesystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +50,7 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function initialize()
|
public function initialize()
|
||||||
{
|
{
|
||||||
|
$this->fetchRootIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,11 +58,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getRootIdentifier()
|
public function getRootIdentifier()
|
||||||
{
|
{
|
||||||
if (null === $this->rootIdentifier) {
|
if ($this->gitDriver) {
|
||||||
$repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository));
|
return $this->gitDriver->getRootIdentifier();
|
||||||
$this->rootIdentifier = $repoData['master_branch'] ?: 'master';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->rootIdentifier;
|
return $this->rootIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +69,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getUrl()
|
public function getUrl()
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getUrl();
|
||||||
|
}
|
||||||
return $this->url;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +80,19 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getSource($identifier)
|
public function getSource($identifier)
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getSource($identifier);
|
||||||
|
}
|
||||||
$label = array_search($identifier, $this->getTags()) ?: $identifier;
|
$label = array_search($identifier, $this->getTags()) ?: $identifier;
|
||||||
|
if ($this->isPrivate) {
|
||||||
|
// Private GitHub repositories should be accessed using the
|
||||||
|
// SSH version of the URL.
|
||||||
|
$url = $this->generateSshUrl();
|
||||||
|
} else {
|
||||||
|
$url = $this->getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $label);
|
return array('type' => 'git', 'url' => $url, 'reference' => $label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,6 +100,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getDist($identifier)
|
public function getDist($identifier)
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getDist($identifier);
|
||||||
|
}
|
||||||
$label = array_search($identifier, $this->getTags()) ?: $identifier;
|
$label = array_search($identifier, $this->getTags()) ?: $identifier;
|
||||||
$url = $this->getScheme() . '://github.com/'.$this->owner.'/'.$this->repository.'/zipball/'.$label;
|
$url = $this->getScheme() . '://github.com/'.$this->owner.'/'.$this->repository.'/zipball/'.$label;
|
||||||
|
|
||||||
|
@ -80,6 +114,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getComposerInformation($identifier)
|
public function getComposerInformation($identifier)
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getComposerInformation($identifier);
|
||||||
|
}
|
||||||
if (!isset($this->infoCache[$identifier])) {
|
if (!isset($this->infoCache[$identifier])) {
|
||||||
$composer = $this->getContents($this->getScheme() . '://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json');
|
$composer = $this->getContents($this->getScheme() . '://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json');
|
||||||
if (!$composer) {
|
if (!$composer) {
|
||||||
|
@ -103,6 +140,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getTags()
|
public function getTags()
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getTags();
|
||||||
|
}
|
||||||
if (null === $this->tags) {
|
if (null === $this->tags) {
|
||||||
$tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'));
|
$tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'));
|
||||||
$this->tags = array();
|
$this->tags = array();
|
||||||
|
@ -119,6 +159,9 @@ class GitHubDriver extends VcsDriver
|
||||||
*/
|
*/
|
||||||
public function getBranches()
|
public function getBranches()
|
||||||
{
|
{
|
||||||
|
if ($this->gitDriver) {
|
||||||
|
return $this->gitDriver->getBranches();
|
||||||
|
}
|
||||||
if (null === $this->branches) {
|
if (null === $this->branches) {
|
||||||
$branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'));
|
$branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'));
|
||||||
$this->branches = array();
|
$this->branches = array();
|
||||||
|
@ -137,4 +180,63 @@ class GitHubDriver extends VcsDriver
|
||||||
{
|
{
|
||||||
return extension_loaded('openssl') && preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url);
|
return extension_loaded('openssl') && preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an SSH URL
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function generateSshUrl()
|
||||||
|
{
|
||||||
|
return 'git@github.com:'.$this->owner.'/'.$this->repository.'.git';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch root identifier from GitHub
|
||||||
|
*
|
||||||
|
* @throws TransportException
|
||||||
|
*/
|
||||||
|
protected function fetchRootIdentifier()
|
||||||
|
{
|
||||||
|
$repoDataUrl = $this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository;
|
||||||
|
$attemptCounter = 0;
|
||||||
|
while (null === $this->rootIdentifier) {
|
||||||
|
if (5 == $attemptCounter++) {
|
||||||
|
throw new \RuntimeException("Either you have entered invalid credentials or this GitHub repository does not exists (404)");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$repoData = JsonFile::parseJson($this->getContents($repoDataUrl));
|
||||||
|
$this->rootIdentifier = $repoData['master_branch'] ?: 'master';
|
||||||
|
} catch (TransportException $e) {
|
||||||
|
switch($e->getCode()) {
|
||||||
|
case 401:
|
||||||
|
case 404:
|
||||||
|
$this->isPrivate = true;
|
||||||
|
if (!$this->io->isInteractive()) {
|
||||||
|
// If this repository may be private (hard to say for sure,
|
||||||
|
// GitHub returns 404 for private repositories) and we
|
||||||
|
// cannot ask for authentication credentials (because we
|
||||||
|
// are not interactive) then we fallback to GitDriver.
|
||||||
|
$this->gitDriver = new GitDriver(
|
||||||
|
$this->generateSshUrl(),
|
||||||
|
$this->io,
|
||||||
|
$this->process,
|
||||||
|
$this->remoteFilesystem
|
||||||
|
);
|
||||||
|
$this->gitDriver->initialize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->io->write('Authentication required (<info>'.$this->url.'</info>):');
|
||||||
|
$username = $this->io->ask('Username: ');
|
||||||
|
$password = $this->io->askAndHideAnswer('Password: ');
|
||||||
|
$this->io->setAuthorization($this->url, $username, $password);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw $e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ abstract class VcsDriver implements VcsDriverInterface
|
||||||
protected $url;
|
protected $url;
|
||||||
protected $io;
|
protected $io;
|
||||||
protected $process;
|
protected $process;
|
||||||
|
protected $remoteFilesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -34,12 +35,14 @@ abstract class VcsDriver implements VcsDriverInterface
|
||||||
* @param string $url The URL
|
* @param string $url The URL
|
||||||
* @param IOInterface $io The IO instance
|
* @param IOInterface $io The IO instance
|
||||||
* @param ProcessExecutor $process Process instance, injectable for mocking
|
* @param ProcessExecutor $process Process instance, injectable for mocking
|
||||||
|
* @param callable $remoteFilesystem Remote Filesystem, injectable for mocking
|
||||||
*/
|
*/
|
||||||
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
|
public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystem = null)
|
||||||
{
|
{
|
||||||
$this->url = $url;
|
$this->url = $url;
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
$this->process = $process ?: new ProcessExecutor;
|
$this->process = $process ?: new ProcessExecutor;
|
||||||
|
$this->remoteFilesystem = $remoteFilesystem ?: new RemoteFilesystem($io);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,8 +83,7 @@ abstract class VcsDriver implements VcsDriverInterface
|
||||||
*/
|
*/
|
||||||
protected function getContents($url)
|
protected function getContents($url)
|
||||||
{
|
{
|
||||||
$rfs = new RemoteFilesystem($this->io);
|
return $this->remoteFilesystem->getContents($this->url, $url, false);
|
||||||
return $rfs->getContents($this->url, $url, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function isLocalUrl($url)
|
protected static function isLocalUrl($url)
|
||||||
|
|
|
@ -80,13 +80,11 @@ class RemoteFilesystem
|
||||||
* @param string $fileUrl The file URL
|
* @param string $fileUrl The file URL
|
||||||
* @param string $fileName the local filename
|
* @param string $fileName the local filename
|
||||||
* @param boolean $progress Display the progression
|
* @param boolean $progress Display the progression
|
||||||
* @param boolean $firstCall Whether this is the first attempt at fetching this resource
|
|
||||||
*
|
*
|
||||||
* @throws TransportException When the file could not be downloaded
|
* @throws TransportException When the file could not be downloaded
|
||||||
*/
|
*/
|
||||||
protected function get($originUrl, $fileUrl, $fileName = null, $progress = true, $firstCall = true)
|
protected function get($originUrl, $fileUrl, $fileName = null, $progress = true)
|
||||||
{
|
{
|
||||||
$this->firstCall = $firstCall;
|
|
||||||
$this->bytesMax = 0;
|
$this->bytesMax = 0;
|
||||||
$this->result = null;
|
$this->result = null;
|
||||||
$this->originUrl = $originUrl;
|
$this->originUrl = $originUrl;
|
||||||
|
@ -102,10 +100,9 @@ class RemoteFilesystem
|
||||||
$this->io->write(" Downloading: <comment>connection...</comment>", false);
|
$this->io->write(" Downloading: <comment>connection...</comment>", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $fileName) {
|
|
||||||
$result = @copy($fileUrl, $fileName, $ctx);
|
|
||||||
} else {
|
|
||||||
$result = @file_get_contents($fileUrl, false, $ctx);
|
$result = @file_get_contents($fileUrl, false, $ctx);
|
||||||
|
if (null !== $fileName) {
|
||||||
|
$result = @file_put_contents($fileName, $result) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix for 5.4.0 https://bugs.php.net/bug.php?id=61336
|
// fix for 5.4.0 https://bugs.php.net/bug.php?id=61336
|
||||||
|
@ -140,20 +137,12 @@ class RemoteFilesystem
|
||||||
protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
|
protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
|
||||||
{
|
{
|
||||||
switch ($notificationCode) {
|
switch ($notificationCode) {
|
||||||
case STREAM_NOTIFY_AUTH_REQUIRED:
|
|
||||||
case STREAM_NOTIFY_FAILURE:
|
case STREAM_NOTIFY_FAILURE:
|
||||||
if (404 === $messageCode && !$this->firstCall) {
|
throw new TransportException(trim($message), $messageCode);
|
||||||
throw new TransportException("The '" . $this->fileUrl . "' URL not found", 404);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// for private repository returning 404 error when the authorization is incorrect
|
case STREAM_NOTIFY_AUTH_REQUIRED:
|
||||||
$auth = $this->io->getAuthorization($this->originUrl);
|
if (401 === $messageCode) {
|
||||||
$attemptAuthentication = $this->firstCall && 404 === $messageCode && null === $auth['username'];
|
|
||||||
|
|
||||||
$this->firstCall = false;
|
|
||||||
|
|
||||||
// get authorization informations
|
|
||||||
if (401 === $messageCode || $attemptAuthentication) {
|
|
||||||
if (!$this->io->isInteractive()) {
|
if (!$this->io->isInteractive()) {
|
||||||
$message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console";
|
$message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console";
|
||||||
|
|
||||||
|
@ -165,7 +154,7 @@ class RemoteFilesystem
|
||||||
$password = $this->io->askAndHideAnswer(' Password: ');
|
$password = $this->io->askAndHideAnswer(' Password: ');
|
||||||
$this->io->setAuthorization($this->originUrl, $username, $password);
|
$this->io->setAuthorization($this->originUrl, $username, $password);
|
||||||
|
|
||||||
$this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progress, false);
|
$this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progress);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function includeIfExists($file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
return include $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!$loader = includeIfExists(__DIR__.'/../../../.composer/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../vendor/.composer/autoload.php'))) {
|
||||||
|
die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
|
||||||
|
'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
|
||||||
|
'php composer.phar install'.PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $loader;
|
|
@ -80,7 +80,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$this->assertEquals($expected, $selected);
|
$this->assertEquals($expected, $selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSelectLastRepo()
|
public function testSelectFirstRepo()
|
||||||
{
|
{
|
||||||
$this->repoImportant = new ArrayRepository;
|
$this->repoImportant = new ArrayRepository;
|
||||||
|
|
||||||
|
@ -88,8 +88,8 @@ class DefaultPolicyTest extends TestCase
|
||||||
$this->repoImportant->addPackage($packageAImportant = $this->getPackage('A', '1.0'));
|
$this->repoImportant->addPackage($packageAImportant = $this->getPackage('A', '1.0'));
|
||||||
|
|
||||||
$this->pool->addRepository($this->repoInstalled);
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
$this->pool->addRepository($this->repo);
|
|
||||||
$this->pool->addRepository($this->repoImportant);
|
$this->pool->addRepository($this->repoImportant);
|
||||||
|
$this->pool->addRepository($this->repo);
|
||||||
|
|
||||||
$literals = array(new Literal($packageA, true), new Literal($packageAImportant, true));
|
$literals = array(new Literal($packageA, true), new Literal($packageAImportant, true));
|
||||||
$expected = array(new Literal($packageAImportant, true));
|
$expected = array(new Literal($packageAImportant, true));
|
||||||
|
|
|
@ -54,7 +54,44 @@ class PoolTest extends TestCase
|
||||||
$secondPriority = $pool->getPriority($secondRepository);
|
$secondPriority = $pool->getPriority($secondRepository);
|
||||||
|
|
||||||
$this->assertEquals(0, $firstPriority);
|
$this->assertEquals(0, $firstPriority);
|
||||||
$this->assertEquals(1, $secondPriority);
|
$this->assertEquals(-1, $secondPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhatProvidesSamePackageForDifferentRepositories()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$firstRepository = new ArrayRepository;
|
||||||
|
$secondRepository = new ArrayRepository;
|
||||||
|
|
||||||
|
$firstPackage = $this->getPackage('foo', '1');
|
||||||
|
$secondPackage = $this->getPackage('foo', '1');
|
||||||
|
$thirdPackage = $this->getPackage('foo', '2');
|
||||||
|
|
||||||
|
$firstRepository->addPackage($firstPackage);
|
||||||
|
$secondRepository->addPackage($secondPackage);
|
||||||
|
$secondRepository->addPackage($thirdPackage);
|
||||||
|
|
||||||
|
$pool->addRepository($firstRepository);
|
||||||
|
$pool->addRepository($secondRepository);
|
||||||
|
|
||||||
|
$this->assertEquals(array($firstPackage, $secondPackage, $thirdPackage), $pool->whatProvides('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhatProvidesPackageWithConstraint()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
|
||||||
|
$firstPackage = $this->getPackage('foo', '1');
|
||||||
|
$secondPackage = $this->getPackage('foo', '2');
|
||||||
|
|
||||||
|
$repository->addPackage($firstPackage);
|
||||||
|
$repository->addPackage($secondPackage);
|
||||||
|
|
||||||
|
$pool->addRepository($repository);
|
||||||
|
|
||||||
|
$this->assertEquals(array($firstPackage, $secondPackage), $pool->whatProvides('foo'));
|
||||||
|
$this->assertEquals(array($secondPackage), $pool->whatProvides('foo', $this->getVersionConstraint('==', '2')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPackageById()
|
public function testPackageById()
|
||||||
|
|
|
@ -47,6 +47,32 @@ class RequestTest extends TestCase
|
||||||
$request->getJobs());
|
$request->getJobs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRequestInstallSamePackageFromDifferentRepositories()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repo1 = new ArrayRepository;
|
||||||
|
$repo2 = new ArrayRepository;
|
||||||
|
|
||||||
|
$foo1 = $this->getPackage('foo', '1');
|
||||||
|
$foo2 = $this->getPackage('foo', '1');
|
||||||
|
|
||||||
|
$repo1->addPackage($foo1);
|
||||||
|
$repo2->addPackage($foo2);
|
||||||
|
|
||||||
|
$pool->addRepository($repo1);
|
||||||
|
$pool->addRepository($repo2);
|
||||||
|
|
||||||
|
$request = new Request($pool);
|
||||||
|
$request->install('foo', $this->getVersionConstraint('=', '1'));
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array(
|
||||||
|
array('packages' => array($foo1, $foo2), 'cmd' => 'install', 'packageName' => 'foo'),
|
||||||
|
),
|
||||||
|
$request->getJobs()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testUpdateAll()
|
public function testUpdateAll()
|
||||||
{
|
{
|
||||||
$pool = new Pool;
|
$pool = new Pool;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
* For the full copyright and license information, please view the LICENSE
|
* For the full copyright and license information, please view the LICENSE
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Composer\Test\DependencyResolver;
|
namespace Composer\Test\DependencyResolver;
|
||||||
|
|
||||||
use Composer\Repository\ArrayRepository;
|
use Composer\Repository\ArrayRepository;
|
||||||
|
@ -70,6 +69,25 @@ class SolverTest extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverInstallSamePackageFromDifferentRepositories()
|
||||||
|
{
|
||||||
|
$repo1 = new ArrayRepository;
|
||||||
|
$repo2 = new ArrayRepository;
|
||||||
|
|
||||||
|
$repo1->addPackage($foo1 = $this->getPackage('foo', '1'));
|
||||||
|
$repo2->addPackage($foo2 = $this->getPackage('foo', '1'));
|
||||||
|
|
||||||
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
|
$this->pool->addRepository($repo1);
|
||||||
|
$this->pool->addRepository($repo2);
|
||||||
|
|
||||||
|
$this->request->install('foo');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'install', 'package' => $foo1),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverInstallWithDeps()
|
public function testSolverInstallWithDeps()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
|
|
@ -17,6 +17,13 @@ use Composer\Util\Filesystem;
|
||||||
|
|
||||||
class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
protected function getDownloader($io = null, $rfs = null)
|
||||||
|
{
|
||||||
|
$io = $io ?: $this->getMock('Composer\IO\IOInterface');
|
||||||
|
$rfs = $rfs ?: $this->getMockBuilder('Composer\Util\RemoteFilesystem')->disableOriginalConstructor()->getMock();
|
||||||
|
return new FileDownloader($io, $rfs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \InvalidArgumentException
|
* @expectedException \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
|
@ -28,7 +35,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
->will($this->returnValue(null))
|
->will($this->returnValue(null))
|
||||||
;
|
;
|
||||||
|
|
||||||
$downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface'));
|
$downloader = $this->getDownloader();
|
||||||
$downloader->download($packageMock, '/path');
|
$downloader->download($packageMock, '/path');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +49,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
$path = tempnam(sys_get_temp_dir(), 'c');
|
$path = tempnam(sys_get_temp_dir(), 'c');
|
||||||
|
|
||||||
$downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface'));
|
$downloader = $this->getDownloader();
|
||||||
try {
|
try {
|
||||||
$downloader->download($packageMock, $path);
|
$downloader->download($packageMock, $path);
|
||||||
$this->fail();
|
$this->fail();
|
||||||
|
@ -63,7 +70,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
->will($this->returnValue('http://example.com/script.js'))
|
->will($this->returnValue('http://example.com/script.js'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface'));
|
$downloader = $this->getDownloader();
|
||||||
$method = new \ReflectionMethod($downloader, 'getFileName');
|
$method = new \ReflectionMethod($downloader, 'getFileName');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
|
@ -93,7 +100,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
}))
|
}))
|
||||||
;
|
;
|
||||||
|
|
||||||
$downloader = new FileDownloader($ioMock);
|
$downloader = $this->getDownloader($ioMock);
|
||||||
try {
|
try {
|
||||||
$downloader->download($packageMock, $path);
|
$downloader->download($packageMock, $path);
|
||||||
$this->fail();
|
$this->fail();
|
||||||
|
@ -126,7 +133,12 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
$path = sys_get_temp_dir().'/'.md5(time().rand());
|
$path = sys_get_temp_dir().'/'.md5(time().rand());
|
||||||
} while (file_exists($path));
|
} while (file_exists($path));
|
||||||
|
|
||||||
$downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface'));
|
$downloader = $this->getDownloader();
|
||||||
|
|
||||||
|
// make sure the file expected to be downloaded is on disk already
|
||||||
|
mkdir($path, 0777, true);
|
||||||
|
touch($path.'/script.js');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$downloader->download($packageMock, $path);
|
$downloader->download($packageMock, $path);
|
||||||
$this->fail();
|
$this->fail();
|
||||||
|
|
|
@ -41,7 +41,6 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testDownload()
|
public function testDownload()
|
||||||
{
|
{
|
||||||
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
|
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
->method('getSourceReference')
|
->method('getSourceReference')
|
||||||
|
@ -50,6 +49,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
->method('getSourceUrl')
|
->method('getSourceUrl')
|
||||||
->will($this->returnValue('https://example.com/composer/composer'));
|
->will($this->returnValue('https://example.com/composer/composer'));
|
||||||
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
|
||||||
|
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
|
||||||
$processExecutor->expects($this->once())
|
$processExecutor->expects($this->once())
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($expectedGitCommand))
|
->with($this->equalTo($expectedGitCommand))
|
||||||
|
@ -59,13 +60,13 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
$downloader->download($packageMock, 'composerPath');
|
$downloader->download($packageMock, 'composerPath');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDownloadUsesVariousProtocolsForGithub()
|
public function testDownloadUsesVariousProtocolsAndSetsPushUrlForGithub()
|
||||||
{
|
{
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
->method('getSourceReference')
|
->method('getSourceReference')
|
||||||
->will($this->returnValue('ref'));
|
->will($this->returnValue('ref'));
|
||||||
$packageMock->expects($this->once())
|
$packageMock->expects($this->any())
|
||||||
->method('getSourceUrl')
|
->method('getSourceUrl')
|
||||||
->will($this->returnValue('https://github.com/composer/composer'));
|
->will($this->returnValue('https://github.com/composer/composer'));
|
||||||
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
@ -88,6 +89,12 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($this->equalTo($expectedGitCommand))
|
->with($this->equalTo($expectedGitCommand))
|
||||||
->will($this->returnValue(0));
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
|
$expectedGitCommand = $this->getCmd("cd 'composerPath' && git remote set-url --push origin 'git@github.com:composer/composer.git'");
|
||||||
|
$processExecutor->expects($this->at(3))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitCommand))
|
||||||
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
$downloader = $this->getDownloaderMock(null, $processExecutor);
|
$downloader = $this->getDownloaderMock(null, $processExecutor);
|
||||||
$downloader->download($packageMock, 'composerPath');
|
$downloader->download($packageMock, 'composerPath');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Test;
|
||||||
|
|
||||||
|
use Composer\Factory;
|
||||||
|
|
||||||
|
class FactoryTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider dataAddPackagistRepository
|
||||||
|
*/
|
||||||
|
public function testAddPackagistRepository($expected, $config)
|
||||||
|
{
|
||||||
|
$factory = new Factory();
|
||||||
|
|
||||||
|
$ref = new \ReflectionMethod($factory, 'addPackagistRepository');
|
||||||
|
$ref->setAccessible(true);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $ref->invoke($factory, $config));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataAddPackagistRepository()
|
||||||
|
{
|
||||||
|
$f = function() {
|
||||||
|
$repositories = func_get_args();
|
||||||
|
return array('repositories' => $repositories);
|
||||||
|
};
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
$data[] = array(
|
||||||
|
$f(array('type' => 'composer', 'url' => 'http://packagist.org')),
|
||||||
|
$f()
|
||||||
|
);
|
||||||
|
|
||||||
|
$data[] = array(
|
||||||
|
$f(array('packagist' => false)),
|
||||||
|
$f(array('packagist' => false))
|
||||||
|
);
|
||||||
|
|
||||||
|
$data[] = array(
|
||||||
|
$f(
|
||||||
|
array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
||||||
|
array('type' => 'composer', 'url' => 'http://packagist.org'),
|
||||||
|
array('type' => 'pear', 'url' => 'http://pear.composer.org')
|
||||||
|
),
|
||||||
|
$f(
|
||||||
|
array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
||||||
|
array('packagist' => true),
|
||||||
|
array('type' => 'pear', 'url' => 'http://pear.composer.org')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Test\Repository\Vcs;
|
||||||
|
|
||||||
|
use Composer\Downloader\TransportException;
|
||||||
|
use Composer\Repository\Vcs\GitHubDriver;
|
||||||
|
use Composer\Util\Filesystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Beau Simensen <beau@dflydev.com>
|
||||||
|
*/
|
||||||
|
class GitHubDriverTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testPrivateRepository()
|
||||||
|
{
|
||||||
|
$scheme = extension_loaded('openssl') ? 'https' : 'http';
|
||||||
|
|
||||||
|
$repoUrl = 'http://github.com/composer/packagist';
|
||||||
|
$repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist';
|
||||||
|
$repoSshUrl = 'git@github.com:composer/packagist.git';
|
||||||
|
$identifier = 'v0.0.0';
|
||||||
|
$sha = 'SOMESHA';
|
||||||
|
|
||||||
|
$io = $this->getMock('Composer\IO\IOInterface');
|
||||||
|
$io->expects($this->any())
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
|
||||||
|
->setConstructorArgs(array($io))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$remoteFilesystem->expects($this->at(0))
|
||||||
|
->method('getContents')
|
||||||
|
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
|
||||||
|
->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
|
||||||
|
|
||||||
|
$io->expects($this->once())
|
||||||
|
->method('ask')
|
||||||
|
->with($this->equalTo('Username: '))
|
||||||
|
->will($this->returnValue('someuser'));
|
||||||
|
|
||||||
|
$io->expects($this->once())
|
||||||
|
->method('askAndHideAnswer')
|
||||||
|
->with($this->equalTo('Password: '))
|
||||||
|
->will($this->returnValue('somepassword'));
|
||||||
|
|
||||||
|
$io->expects($this->once())
|
||||||
|
->method('setAuthorization')
|
||||||
|
->with($this->equalTo($repoUrl), 'someuser', 'somepassword');
|
||||||
|
|
||||||
|
$remoteFilesystem->expects($this->at(1))
|
||||||
|
->method('getContents')
|
||||||
|
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
|
||||||
|
->will($this->returnValue('{"master_branch": "test_master"}'));
|
||||||
|
|
||||||
|
$gitHubDriver = new GitHubDriver($repoUrl, $io, null, $remoteFilesystem);
|
||||||
|
$gitHubDriver->initialize();
|
||||||
|
$this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
|
||||||
|
|
||||||
|
$this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
|
||||||
|
|
||||||
|
$dist = $gitHubDriver->getDist($identifier);
|
||||||
|
$this->assertEquals('zip', $dist['type']);
|
||||||
|
$this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']);
|
||||||
|
$this->assertEquals('v0.0.0', $dist['reference']);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($identifier);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoSshUrl, $source['url']);
|
||||||
|
$this->assertEquals('v0.0.0', $source['reference']);
|
||||||
|
|
||||||
|
$dist = $gitHubDriver->getDist($sha);
|
||||||
|
$this->assertEquals('zip', $dist['type']);
|
||||||
|
$this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']);
|
||||||
|
$this->assertEquals('v0.0.0', $dist['reference']);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($sha);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoSshUrl, $source['url']);
|
||||||
|
$this->assertEquals('v0.0.0', $source['reference']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPublicRepository()
|
||||||
|
{
|
||||||
|
$scheme = extension_loaded('openssl') ? 'https' : 'http';
|
||||||
|
|
||||||
|
$repoUrl = 'http://github.com/composer/packagist';
|
||||||
|
$repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist';
|
||||||
|
$identifier = 'v0.0.0';
|
||||||
|
$sha = 'SOMESHA';
|
||||||
|
|
||||||
|
$io = $this->getMock('Composer\IO\IOInterface');
|
||||||
|
$io->expects($this->any())
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
|
||||||
|
->setConstructorArgs(array($io))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$remoteFilesystem->expects($this->at(0))
|
||||||
|
->method('getContents')
|
||||||
|
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
|
||||||
|
->will($this->returnValue('{"master_branch": "test_master"}'));
|
||||||
|
|
||||||
|
$gitHubDriver = new GitHubDriver($repoUrl, $io, null, $remoteFilesystem);
|
||||||
|
$gitHubDriver->initialize();
|
||||||
|
$this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
|
||||||
|
|
||||||
|
$this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
|
||||||
|
|
||||||
|
$dist = $gitHubDriver->getDist($identifier);
|
||||||
|
$this->assertEquals('zip', $dist['type']);
|
||||||
|
$this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']);
|
||||||
|
$this->assertEquals($identifier, $dist['reference']);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($identifier);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoUrl, $source['url']);
|
||||||
|
$this->assertEquals($identifier, $source['reference']);
|
||||||
|
|
||||||
|
$dist = $gitHubDriver->getDist($sha);
|
||||||
|
$this->assertEquals('zip', $dist['type']);
|
||||||
|
$this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']);
|
||||||
|
$this->assertEquals($identifier, $dist['reference']);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($sha);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoUrl, $source['url']);
|
||||||
|
$this->assertEquals($identifier, $source['reference']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPrivateRepositoryNoInteraction()
|
||||||
|
{
|
||||||
|
$scheme = extension_loaded('openssl') ? 'https' : 'http';
|
||||||
|
|
||||||
|
$repoUrl = 'http://github.com/composer/packagist';
|
||||||
|
$repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist';
|
||||||
|
$repoSshUrl = 'git@github.com:composer/packagist.git';
|
||||||
|
$identifier = 'v0.0.0';
|
||||||
|
$sha = 'SOMESHA';
|
||||||
|
|
||||||
|
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$io = $this->getMock('Composer\IO\IOInterface');
|
||||||
|
$io->expects($this->any())
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
|
||||||
|
->setConstructorArgs(array($io))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$remoteFilesystem->expects($this->at(0))
|
||||||
|
->method('getContents')
|
||||||
|
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
|
||||||
|
->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
|
||||||
|
|
||||||
|
// clean local clone if present
|
||||||
|
$fs = new Filesystem();
|
||||||
|
$fs->removeDirectory(sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $repoSshUrl) . '/');
|
||||||
|
|
||||||
|
$process->expects($this->at(0))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->stringContains($repoSshUrl));
|
||||||
|
|
||||||
|
$process->expects($this->at(1))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->stringContains('git tag'));
|
||||||
|
|
||||||
|
$process->expects($this->at(2))
|
||||||
|
->method('splitLines')
|
||||||
|
->will($this->returnValue(array($identifier)));
|
||||||
|
|
||||||
|
$process->expects($this->at(3))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->stringContains('git branch'));
|
||||||
|
|
||||||
|
$process->expects($this->at(4))
|
||||||
|
->method('splitLines')
|
||||||
|
->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior')));
|
||||||
|
|
||||||
|
$process->expects($this->at(5))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->stringContains('git branch'));
|
||||||
|
|
||||||
|
$process->expects($this->at(6))
|
||||||
|
->method('splitLines')
|
||||||
|
->will($this->returnValue(array(' upstream/HEAD -> upstream/test_master')));
|
||||||
|
|
||||||
|
$gitHubDriver = new GitHubDriver($repoUrl, $io, $process, $remoteFilesystem);
|
||||||
|
$gitHubDriver->initialize();
|
||||||
|
|
||||||
|
$this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
|
||||||
|
|
||||||
|
// Dist is not available for GitDriver
|
||||||
|
$dist = $gitHubDriver->getDist($identifier);
|
||||||
|
$this->assertNull($dist);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($identifier);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoSshUrl, $source['url']);
|
||||||
|
$this->assertEquals($identifier, $source['reference']);
|
||||||
|
|
||||||
|
// Dist is not available for GitDriver
|
||||||
|
$dist = $gitHubDriver->getDist($sha);
|
||||||
|
$this->assertNull($dist);
|
||||||
|
|
||||||
|
$source = $gitHubDriver->getSource($sha);
|
||||||
|
$this->assertEquals('git', $source['type']);
|
||||||
|
$this->assertEquals($repoSshUrl, $source['url']);
|
||||||
|
$this->assertEquals($sha, $source['reference']);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setAttribute($object, $attribute, $value)
|
||||||
|
{
|
||||||
|
$attr = new \ReflectionProperty($object, $attribute);
|
||||||
|
$attr->setAccessible(true);
|
||||||
|
$attr->setValue($object, $value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,41 +105,14 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
|
||||||
public function testCallbackGetNotifyFailure404()
|
public function testCallbackGetNotifyFailure404()
|
||||||
{
|
{
|
||||||
$fs = new RemoteFilesystem($this->getMock('Composer\IO\IOInterface'));
|
$fs = new RemoteFilesystem($this->getMock('Composer\IO\IOInterface'));
|
||||||
$this->setAttribute($fs, 'firstCall', false);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0);
|
$this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, 'HTTP/1.1 404 Not Found', 404, 0, 0);
|
||||||
$this->fail();
|
$this->fail();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->assertInstanceOf('Composer\Downloader\TransportException', $e);
|
$this->assertInstanceOf('Composer\Downloader\TransportException', $e);
|
||||||
$this->assertContains('URL not found', $e->getMessage());
|
$this->assertEquals(404, $e->getCode());
|
||||||
}
|
$this->assertContains('HTTP/1.1 404 Not Found', $e->getMessage());
|
||||||
}
|
|
||||||
|
|
||||||
public function testCallbackGetNotifyFailure404FirstCall()
|
|
||||||
{
|
|
||||||
$io = $this->getMock('Composer\IO\IOInterface');
|
|
||||||
$io
|
|
||||||
->expects($this->once())
|
|
||||||
->method('getAuthorization')
|
|
||||||
->will($this->returnValue(array('username' => null)))
|
|
||||||
;
|
|
||||||
$io
|
|
||||||
->expects($this->once())
|
|
||||||
->method('isInteractive')
|
|
||||||
->will($this->returnValue(false))
|
|
||||||
;
|
|
||||||
|
|
||||||
$fs = new RemoteFilesystem($io);
|
|
||||||
$this->setAttribute($fs, 'firstCall', true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0);
|
|
||||||
$this->fail();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->assertInstanceOf('Composer\Downloader\TransportException', $e);
|
|
||||||
$this->assertContains('URL required authentication', $e->getMessage());
|
|
||||||
$this->assertAttributeEquals(false, 'firstCall', $fs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,5 @@
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((!$loader = @include __DIR__.'/../../../.composer/autoload.php') && (!$loader = @include __DIR__.'/../vendor/.composer/autoload.php')) {
|
$loader = require __DIR__.'/../src/bootstrap.php';
|
||||||
die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
|
|
||||||
'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
|
|
||||||
'php composer.phar install'.PHP_EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
$loader->add('Composer\Test', __DIR__);
|
$loader->add('Composer\Test', __DIR__);
|
||||||
|
|
Loading…
Reference in New Issue