1
0
Fork 0

Merged in upstream

pull/649/head
Maxim Chernyshev 2012-05-02 08:36:05 +08:00
commit 2ca50a1ef3
80 changed files with 1305 additions and 453 deletions

View File

@ -7,6 +7,6 @@ php:
before_script:
- wget -nc http://getcomposer.org/composer.phar
- php composer.phar update
- php composer.phar install
script: phpunit

View File

@ -3,10 +3,17 @@
* Schema: Added 'require-dev' for development-time requirements (tests, etc), install with --dev
* Schema: Removed 'recommend'
* Schema: 'suggest' is now informational and can use any description for a package, not only a constraint
* Break: vendor/.composer/autoload.php has been moved to vendor/autoload.php, other files are now in vendor/composer/
* Added caching of repository metadata (faster startup times & failover if packagist is down)
* Added removal of packages that are not needed anymore
* Added include_path support for legacy projects that are full of require_once statements
* Added installation notifications API to allow better statistics on Composer repositories
* Added autoloading support for root packages that use target-dir
* Added awareness of the root package presence and support for it's provide/replace/conflict keys
* Added IOInterface::isDecorated to test for colored output support
* Improved repository protocol to have large cacheable parts
* Fixed various bugs relating to package aliasing, proxy configuration, binaries
* Various bug fixes and docs improvements
* 1.0.0-alpha2 (2012-04-03)

8
composer.lock generated
View File

@ -1,5 +1,5 @@
{
"hash": "c4a3809551d45254dd0b45eb282d6285",
"hash": "1350b672ef2fc5723334092cb18c3bca",
"packages": [
{
"package": "justinrainbow/json-schema",
@ -12,19 +12,19 @@
{
"package": "symfony/console",
"version": "dev-master",
"source-reference": "8e3c42aa976f18a9bfcb0694553e5f99def3309c",
"source-reference": "eaad4427b10ff39402bce0ae4f8cd1faf2b6532a",
"alias": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/finder",
"version": "dev-master",
"source-reference": "57ec7198a70e6c40e450ba66cc2f8ecab98746c8",
"source-reference": "78b2e33951821b6d423718f57788f1894dcb935a",
"alias": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/process",
"version": "dev-master",
"source-reference": "2e4da8c8076744bafed97451bb1574c96cda0e68",
"source-reference": "718655f4bc664d693b33f3e6e8a895e454208021",
"alias": "2.1.9999999.9999999-dev"
}
],

View File

@ -80,7 +80,7 @@ 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/autoload.php';
Woh! Now start using monolog! To keep learning more about Composer, keep
reading the "Basic Usage" chapter.

View File

@ -108,7 +108,7 @@ same version of the dependencies.
If no `composer.json` lock file exists, it will read the dependencies and
versions from `composer.json` and create the lock file.
This means that if any of the dependencies get a new version, you won't get the updates.
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.
@ -136,10 +136,10 @@ but it makes life quite a bit simpler.
## Autoloading
For libraries that specify autoload information, Composer generates a
`vendor/.composer/autoload.php` file. You can simply include this file and you
`vendor/autoload.php` file. You can simply include this file and you
will get autoloading for free.
require 'vendor/.composer/autoload.php';
require 'vendor/autoload.php';
This makes it really easy to use third party code. For example: If your
project depends on monolog, you can just start using classes from it, and they
@ -168,13 +168,13 @@ be in your project root. An example filename would be `src/Acme/Foo.php`
containing an `Acme\Foo` class.
After adding the `autoload` field, you have to re-run `install` to re-generate
the `vendor/.composer/autoload.php` file.
the `vendor/autoload.php` file.
Including that file will also return the autoloader instance, so you can store
the return value of the include call in a variable and add more namespaces.
This can be useful for autoloading classes in a test suite, for example.
$loader = require 'vendor/.composer/autoload.php';
$loader = require 'vendor/autoload.php';
$loader->add('Acme\Test', __DIR__);
In addition to PSR-0 autoloading, classmap is also supported. This allows
@ -182,7 +182,7 @@ classes to be autoloaded even if they do not conform to PSR-0. See the
[autoload reference](04-schema.md#autoload) for more details.
> **Note:** Composer provides its own autoloader. If you don't want to use
that one, you can just include `vendor/.composer/autoload_namespaces.php`,
that one, you can just include `vendor/autoload_namespaces.php`,
which returns an associative array mapping namespaces to directories.
← [Intro](00-intro.md) | [Libraries](02-libraries.md) →

View File

@ -76,6 +76,14 @@ Here are some examples of version branch names:
> **Note:** When you install a dev version, it will install it from source.
See [Repositories](05-repositories.md) for more information.
### Aliases
It is possible alias branch names to versions. For example, you could alias
`dev-master` to `1.0-dev`, which would allow you to require `1.0-dev` in all
the packages.
See [Aliases](articles/aliases.md) for more information.
## Lock file
For your library you may commit the `composer.lock` file if you want to. This

View File

@ -199,11 +199,6 @@ directory other than `vendor`.
By setting this option you can change the `bin` ([Vendor Bins](articles/vendor-bins.md))
directory to something other than `vendor/bin`.
### COMPOSER_PROCESS_TIMEOUT
This env var controls the time composer waits for commands (such as git
commands) to finish executing. The default value is 60 seconds.
### http_proxy or HTTP_PROXY
If you are using composer from behind an HTTP proxy, you can use the standard
@ -215,4 +210,19 @@ some tools like git or curl will only use the lower-cased `http_proxy` version.
Alternatively you can also define the git proxy using
`git config --global http.proxy <proxy url>`.
### COMPOSER_HOME
The `COMPOSER_HOME` var allows you to change the composer home directory. This
is a hidden, global (per-user on the machine) directory that is shared between
all projects.
By default it points to `/home/<user>/.composer` on *nix,
`/Users/<user>/.composer` on OSX and
`C:\Users\<user>\AppData\Roaming\Composer` on Windows.
### COMPOSER_PROCESS_TIMEOUT
This env var controls the time composer waits for commands (such as git
commands) to finish executing. The default value is 300 seconds (5 minutes).
&larr; [Libraries](02-libraries.md) | [Schema](04-schema.md) &rarr;

View File

@ -145,6 +145,7 @@ Each author object can have following properties:
* **name:** The author's name. Usually his real name.
* **email:** The author's email address.
* **homepage:** An URL to the author's website.
* **role:** The authors' role in the project (e.g. developer or translator)
An example:
@ -153,12 +154,14 @@ An example:
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
"homepage": "http://www.naderman.de",
"role": "Developer"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
"homepage": "http://seld.be",
"role": "Developer"
}
]
}
@ -215,21 +218,26 @@ Example:
Autoload mapping for a PHP autoloader.
Currently [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
autoloading and classmap generation are supported.
autoloading and classmap generation are supported. PSR-0 is the recommended way though
since it offers greater flexibility (no need to regenerate the autoloader when you add
classes).
Under the `psr-0` key you define a mapping from namespaces to paths, relative to the
package root.
package root. Note that this also supports the PEAR-style convention.
Example:
{
"autoload": {
"psr-0": { "Monolog": "src/" }
"psr-0": {
"Monolog": "src/",
"Vendor\\Namespace": "src/",
"Pear_Style": "src/"
}
}
}
Optional, but it is highly recommended that you follow PSR-0 and use this.
If you need to search for a same namespace prefix in multiple directories,
If you need to search for a same prefix in multiple directories,
you can specify them as an array as such:
{
@ -238,15 +246,24 @@ you can specify them as an array as such:
}
}
If you want to have a fallback directory where any namespace can be, you can
use an empty prefix like:
{
"autoload": {
"psr-0": { "": "src/" }
}
}
You can use the classmap generation support to define autoloading for all libraries
that do not follow PSR-0. To configure this you specify all directories
that do not follow PSR-0. To configure this you specify all directories or files
to search for classes.
Example:
{
"autoload: {
"classmap": ["src/", "lib/"]
"classmap": ["src/", "lib/", "Something.php"]
}
}
@ -368,6 +385,9 @@ The following options are supported:
* **process-timeout:** Defaults to `300`. The duration processes like git clones
can run before Composer assumes they died out. You may need to make this
higher if you have a slow connection or huge vendors.
* **notify-on-install:** Defaults to `true`. Composer allows repositories to
define a notification URL, so that they get notified whenever a package from
that repository is installed. This option allows you to disable that behaviour.
Example:

View File

@ -54,15 +54,24 @@ want to learn why.
### Composer
The main repository type is the `composer` repository. It uses a single
`packages.json` file that contains all of the package metadata. The JSON
format is as follows:
`packages.json` file that contains all of the package metadata.
This is also the repository type that packagist uses. To reference a
`composer` repository, just supply the path before the `packages.json` file.
In case of packagist, that file is located at `/packages.json`, so the URL of
the repository would be `packagist.org`. For `example.org/packages.json` the
repository URL would be `example.org`.
#### packages
The only required field is `packages`. The JSON structure is as follows:
{
"packages": {
"vendor/packageName": {
"name": "vendor/packageName",
"description": "Package description",
"versions": {
"master-dev": { @composer.json },
"1.0.x-dev": { @composer.json },
"0.0.1": { @composer.json },
"1.0.0": { @composer.json }
}
}
@ -88,12 +97,54 @@ Here is a minimal package definition:
It may include any of the other fields specified in the [schema](04-schema.md).
The `composer` repository is also what packagist uses. To reference a
`composer` repository, just supply the path before the `packages.json` file.
In case of packagist, that file is located at `/packages.json`, so the URL of
the repository would be `http://packagist.org`. For
`http://example.org/packages.json` the repository URL would be
`http://example.org`.
#### notify
The `notify` field allows you to specify an URL template for a URL that will
be called every time a user installs a package.
An example value:
{
"notify": "/downloads/%package%"
}
For `example.org/packages.json` containing a `monolog/monolog` package, this
would send a `POST` request to `example.org/downloads/monolog/monolog` with
following parameters:
* **version:** The version of the package.
* **version_normalized:** The normalized internal representation of the
version.
This field is optional.
#### includes
For large repositories it is possible to split the `packages.json` into
multiple files. The `includes` field allows you to reference these additional
files.
An example:
{
"includes": {
"packages-2011.json": {
"sha1": "525a85fb37edd1ad71040d429928c2c0edec9d17"
},
"packages-2012-01.json": {
"sha1": "897cde726f8a3918faf27c803b336da223d400dd"
},
"packages-2012-02.json": {
"sha1": "26f911ad717da26bbcac3f8f435280d13917efa5"
}
}
}
The SHA-1 sum of the file allows it to be cached and only re-requested if the
hash changed.
This field is optional. You probably don't need it for your own custom
repository.
### VCS

90
doc/articles/aliases.md Normal file
View File

@ -0,0 +1,90 @@
<!--
tagline: Alias branch names to versions
-->
# Aliases
## Why aliases?
When you are using a VCS repository, you will only get comparable versions for
branches that look like versions, such as `2.0`. For your `master` branch, you
will get a `dev-master` version. For your `bugfix` branch, you will get a
`dev-bugfix` version.
If your `master` branch is used to tag releases of the `1.0` development line,
i.e. `1.0.1`, `1.0.2`, `1.0.3`, etc., any package depending on it will
probably require version `1.0.*`.
If anyone wants to require the latest `dev-master`, they have a problem: Other
packages may require `1.0.*`, so requiring that dev version will lead to
conflicts, since `dev-master` does not match the `1.0.*` constraint.
Enter aliases.
## Branch alias
The `dev-master` branch is one in your main VCS repo. It is rather common that
someone will want the latest master dev version. Thus, Composer allows you to
alias your `dev-master` branch to a `1.0.x-dev` version. It is done by
specifying a `branch-alias` field under `extra` in `composer.json`:
{
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
The branch version must begin with `dev-` (non-comparable version), the alias
must be a comparable dev version. The `branch-alias` must be present on the
branch that it references. For `dev-master`, you need to commit it on the
`master` branch.
As a result, you can now require `1.0.*` and it will happily install
`dev-master` for you.
## Require inline alias
Branch aliases are great for aliasing main development lines. But in order to
use them you need to have control over the source repository, and you need to
commit changes to version control.
This is not really fun when you just want to try a bugfix of some library that
is a dependency of your local project.
For this reason, you can alias packages in your `require` and `require-dev`
fields. Let's say you found a bug in the `monolog/monolog` package. You cloned
Monolog on GitHub and fixed the issue in a branch named `bugfix`. Now you want
to install that version of monolog in your local project.
You are using `symfony/monolog-bundle` which requires `monolog/monolog` version
`1.*`. So you need your `dev-bugfix` to match that constraint.
Just add this to your project's root `composer.json`:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/you/monolog"
}
],
"require": {
"symfony/monolog-bundle": "2.0",
"monolog/monolog": "dev-bugfix as 1.0.x-dev"
}
}
That will fetch the `dev-bugfix` version of `monolog/monolog` from your GitHub
and alias it to `1.0.x-dev`.
> **Note:** If a package with inline aliases is required, the alias (right of
> the `as`) is used as the version constraint. The part left of the `as` is
> discarded. As a consequence, if A requires B and B requires `monolog/monolog`
> version `dev-bugfix as 1.0.x-dev`, installing A will make B require
> `1.0.x-dev`, which may exist as a branch alias or an actual `1.0` branch. If
> it does not, it must be re-inline-aliased in A's `composer.json`.
> **Note:** Inline aliasing should be avoided, especially for published
> packages. If you found a bug, try and get your fix merged upstream. This
> helps to avoid issues for users of your package.

View File

@ -5,7 +5,8 @@
Satis can be used to host the metadata of your company's private packages, or
your own. It basically acts as a micro-packagist. You can get it from
[GitHub](http://github.com/composer/satis).
[GitHub](http://github.com/composer/satis) or install via CLI:
`composer.phar create-project composer/satis`.
## Setup
@ -13,12 +14,29 @@ For example let's assume you have a few packages you want to reuse across your
company but don't really want to open-source. You would first define a Satis
configuration file, which is basically a stripped-down version of a
`composer.json` file. It contains a few repositories, and then you use the require
key to say which packages it should dump in the static repository it creates.
key to say which packages it should dump in the static repository it creates, or
use require-all to select all of them.
Here is an example configuration, you see that it holds a few VCS repositories,
but those could be any types of [repositories](../05-repositories.md). Then
the require just lists all the packages we need, using a `"*"` constraint to
make sure all versions are selected.
but those could be any types of [repositories](../05-repositories.md). Then it
uses `"require-all": true` which selects all versions of all packages in the
repositories you defined.
{
"name": "My Repository",
"homepage": "http://packages.example.org",
"repositories": [
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo" },
{ "type": "vcs", "url": "http://svn.example.org/private/repo" },
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo2" }
],
"require-all": true
}
If you want to cherry pick which packages you want, you can list all the packages
you want to have in your satis repository inside the classic composer `require` key,
using a `"*"` constraint to make sure all versions are selected, or another
constraint if you want really specific versions.
{
"repositories": [
@ -29,7 +47,7 @@ make sure all versions are selected.
"require": {
"company/package": "*",
"company/package2": "*",
"company/package3": "*"
"company/package3": "2.0.0"
}
}

View File

@ -66,6 +66,10 @@
"type": "string",
"description": "Homepage URL for the author.",
"format": "uri"
},
"role": {
"type": "string",
"description": "Author's role in the project."
}
}
}

View File

@ -25,25 +25,26 @@ use Composer\Util\Filesystem;
*/
class AutoloadGenerator
{
public function dump(RepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir)
public function dump(RepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $bcLinks = false)
{
$filesystem = new Filesystem();
$filesystem->ensureDirectoryExists($installationManager->getVendorPath());
$filesystem->ensureDirectoryExists($targetDir);
$vendorPath = strtr(realpath($installationManager->getVendorPath()), '\\', '/');
$relVendorPath = $filesystem->findShortestPath(getcwd(), $vendorPath, true);
$vendorDirCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
$vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
$vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);
$appBaseDir = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
$appBaseDir = str_replace('__DIR__', '$vendorDir', $appBaseDir);
$appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
$appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);
$namespacesFile = <<<EOF
<?php
// autoload_namespace.php generated by Composer
\$vendorDir = $vendorDirCode;
\$baseDir = $appBaseDir;
\$vendorDir = $vendorPathCode;
\$baseDir = $appBaseDirCode;
return array(
@ -55,22 +56,7 @@ EOF;
foreach ($autoloads['psr-0'] as $namespace => $paths) {
$exportedPaths = array();
foreach ($paths as $path) {
$path = strtr($path, '\\', '/');
$baseDir = '';
if (!$filesystem->isAbsolutePath($path)) {
if (strpos($path, $relVendorPath) === 0) {
// path starts with vendor dir
$path = substr($path, strlen($relVendorPath));
$baseDir = '$vendorDir . ';
} else {
$path = '/'.$path;
$baseDir = '$baseDir . ';
}
} elseif (strpos($path, $vendorPath) === 0) {
$path = substr($path, strlen($vendorPath));
$baseDir = '$vendorDir . ';
}
$exportedPaths[] = $baseDir.var_export($path, true);
$exportedPaths[] = $this->getPathCode($filesystem, $relVendorPath, $vendorPath, $path);
}
$exportedPrefix = var_export($namespace, true);
$namespacesFile .= " $exportedPrefix => ";
@ -87,13 +73,44 @@ EOF;
// autoload_classmap.php generated by Composer
\$vendorDir = $vendorDirCode;
\$baseDir = $appBaseDir;
\$vendorDir = $vendorPathCode;
\$baseDir = $appBaseDirCode;
return array(
EOF;
// add custom psr-0 autoloading if the root package has a target dir
$targetDirLoader = null;
$mainAutoload = $mainPackage->getAutoload();
if ($mainPackage->getTargetDir() && $mainAutoload['psr-0']) {
$levels = count(explode('/', trim(strtr($mainPackage->getTargetDir(), '\\', '/'), '/')));
$prefixes = implode(', ', array_map(function ($prefix) {
return var_export($prefix, true);
}, array_keys($mainAutoload['psr-0'])));
$baseDirFromVendorDirCode = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
$targetDirLoader = <<<EOF
spl_autoload_register(function(\$class) {
\$dir = $baseDirFromVendorDirCode . '/';
\$prefixes = array($prefixes);
foreach (\$prefixes as \$prefix) {
if (0 !== strpos(\$class, \$prefix)) {
continue;
}
\$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
if (!stream_resolve_include_path(\$path)) {
return false;
}
require_once \$path;
return true;
}
});
EOF;
}
// flatten array
$autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap']));
foreach ($autoloads['classmap'] as $dir) {
@ -106,11 +123,23 @@ EOF;
file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);
if ($includePathFile = $this->getIncludePathsFile($packageMap)) {
if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $relVendorPath, $vendorPath, $vendorPathCode, $appBaseDirCode)) {
file_put_contents($targetDir.'/include_paths.php', $includePathFile);
}
file_put_contents($targetDir.'/autoload.php', $this->getAutoloadFile(true, true, (Boolean) $includePathFile));
file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, true, true, (Boolean) $includePathFile, $targetDirLoader));
copy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
// TODO BC feature, add E_DEPRECATED in autoload.php on April 30th, remove after May 30th
if ($bcLinks) {
$filesystem->ensureDirectoryExists($vendorPath.'/.composer');
file_put_contents($vendorPath.'/.composer/autoload_namespaces.php', "<?php\n// Deprecated file, use the one in root of vendor dir\nreturn include dirname(__DIR__).'/composer/autoload_namespaces.php';\n");
file_put_contents($vendorPath.'/.composer/autoload_classmap.php', "<?php\n// Deprecated file, use the one in root of vendor dir\nreturn include dirname(__DIR__).'/composer/autoload_classmap.php';\n");
file_put_contents($vendorPath.'/.composer/autoload.php', "<?php\n// Deprecated file, use the one in root of vendor dir\nreturn include dirname(__DIR__).'/autoload.php';\n");
file_put_contents($vendorPath.'/.composer/ClassLoader.php', "<?php\n// Deprecated file, use the one in root of vendor dir\nreturn include dirname(__DIR__).'/composer/ClassLoader.php';\n");
if ($includePathFile) {
file_put_contents($vendorPath.'/.composer/include_paths.php', "<?php\n// Deprecated file, use the one in root of vendor dir\nreturn include dirname(__DIR__).'/composer/include_paths.php';\n");
}
}
}
public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
@ -148,6 +177,10 @@ EOF;
}
foreach ($package->getAutoload() as $type => $mapping) {
// skip misconfigured packages
if (!is_array($mapping)) {
continue;
}
foreach ($mapping as $namespace => $paths) {
foreach ((array) $paths as $path) {
$autoloads[$type][$namespace][] = empty($installPath) ? $path : $installPath.'/'.$path;
@ -182,7 +215,7 @@ EOF;
return $loader;
}
protected function getIncludePathsFile(array $packageMap)
protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, $relVendorPath, $vendorPath, $vendorPathCode, $appBaseDirCode)
{
$includePaths = array();
@ -194,6 +227,7 @@ EOF;
}
foreach ($package->getIncludePaths() as $includePath) {
$includePath = trim($includePath, '/');
$includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath;
}
}
@ -202,30 +236,65 @@ EOF;
return;
}
return sprintf(
"<?php\nreturn %s;\n", var_export($includePaths, true)
);
$includePathsFile = <<<EOF
<?php
// include_paths.php generated by Composer
\$vendorDir = $vendorPathCode;
\$baseDir = $appBaseDirCode;
return array(
EOF;
foreach ($includePaths as $path) {
$includePathsFile .= " " . $this->getPathCode($filesystem, $relVendorPath, $vendorPath, $path) . ",\n";
}
protected function getAutoloadFile($usePSR0, $useClassMap, $useIncludePath)
return $includePathsFile . ");\n";
}
protected function getPathCode(Filesystem $filesystem, $relVendorPath, $vendorPath, $path)
{
$file = <<<'HEADER'
$path = strtr($path, '\\', '/');
$baseDir = '';
if (!$filesystem->isAbsolutePath($path)) {
if (strpos($path, $relVendorPath) === 0) {
// path starts with vendor dir
$path = substr($path, strlen($relVendorPath));
$baseDir = '$vendorDir . ';
} else {
$path = '/'.$path;
$baseDir = '$baseDir . ';
}
} elseif (strpos($path, $vendorPath) === 0) {
$path = substr($path, strlen($vendorPath));
$baseDir = '$vendorDir . ';
}
return $baseDir.var_export($path, true);
}
protected function getAutoloadFile($vendorPathToTargetDirCode, $usePSR0, $useClassMap, $useIncludePath, $targetDirLoader)
{
$file = <<<HEADER
<?php
// autoload.php generated by Composer
if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
require __DIR__.'/ClassLoader.php';
if (!class_exists('Composer\\\\Autoload\\\\ClassLoader', false)) {
require $vendorPathToTargetDirCode . '/ClassLoader.php';
}
return call_user_func(function() {
$loader = new \Composer\Autoload\ClassLoader();
\$loader = new \\Composer\\Autoload\\ClassLoader();
\$composerDir = $vendorPathToTargetDirCode;
HEADER;
if ($useIncludePath) {
$file .= <<<'INCLUDE_PATH'
$includePaths = require __DIR__.'/include_paths.php';
$includePaths = require $composerDir . '/include_paths.php';
array_unshift($includePaths, get_include_path());
set_include_path(join(PATH_SEPARATOR, $includePaths));
@ -235,7 +304,7 @@ INCLUDE_PATH;
if ($usePSR0) {
$file .= <<<'PSR0'
$map = require __DIR__.'/autoload_namespaces.php';
$map = require $composerDir . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->add($namespace, $path);
}
@ -246,7 +315,7 @@ PSR0;
if ($useClassMap) {
$file .= <<<'CLASSMAP'
$classMap = require __DIR__.'/autoload_classmap.php';
$classMap = require $composerDir . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
@ -255,6 +324,8 @@ PSR0;
CLASSMAP;
}
$file .= $targetDirLoader;
return $file . <<<'FOOTER'
$loader->register();

View File

@ -18,6 +18,7 @@ use Composer\Installer\ProjectInstaller;
use Composer\IO\IOInterface;
use Composer\Repository\ComposerRepository;
use Composer\Repository\FilesystemRepository;
use Composer\Repository\InstalledFilesystemRepository;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -82,12 +83,13 @@ EOT
$dm->setPreferSource(true);
}
$config = Factory::createConfig();
if (null === $repositoryUrl) {
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'), $io);
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'), $io, $config);
} elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION)) {
$sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl, new RemoteFilesystem($io)));
} elseif (0 === strpos($repositoryUrl, 'http')) {
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io);
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io, $config);
} else {
throw new \InvalidArgumentException("Invalid repository url given. Has to be a .json file or an http url.");
}
@ -112,7 +114,7 @@ EOT
$io->write('<info>Installing ' . $package->getName() . ' as new project.</info>', true);
$projectInstaller = new ProjectInstaller($directory, $dm);
$projectInstaller->install($package);
$projectInstaller->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), $package);
$io->write('<info>Created project into directory ' . $directory . '</info>', true);
chdir($directory);

View File

@ -13,6 +13,7 @@
namespace Composer\Command;
use Composer\Json\JsonFile;
use Composer\Factory;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\ComposerRepository;
@ -34,7 +35,7 @@ class InitCommand extends Command
public function parseAuthorString($author)
{
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') || version_compare(PHP_VERSION, '5.3.3', '<') || $match['email'] === filter_var($match['email'], FILTER_VALIDATE_EMAIL)) {
return array(
'name' => trim($match['name']),
'email' => $match['email']
@ -229,7 +230,7 @@ EOT
if (!$this->repos) {
$this->repos = new CompositeRepository(array(
new PlatformRepository,
new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO())
new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO(), Factory::createConfig())
));
}

View File

@ -20,6 +20,7 @@ use Composer\Repository\PlatformRepository;
use Composer\Repository\ComposerRepository;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Factory;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
@ -54,7 +55,7 @@ EOT
} else {
$output->writeln('No composer.json found in the current directory, showing packages from packagist.org');
$installedRepo = $platformRepo;
$packagist = new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO());
$packagist = new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO(), Factory::createConfig());
$repos = new CompositeRepository(array($installedRepo, $packagist));
}

View File

@ -53,7 +53,7 @@ EOT
$rfs->copy('getcomposer.org', $remoteFilename, $tempFilename);
try {
chmod($tempFilename, 0755);
chmod($tempFilename, 0777 & ~umask());
// test the phar validity
$phar = new \Phar($tempFilename);
// free the variable to unlock the file

View File

@ -13,6 +13,7 @@
namespace Composer\Command;
use Composer\Composer;
use Composer\Factory;
use Composer\Package\PackageInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
@ -65,7 +66,7 @@ EOT
} else {
$output->writeln('No composer.json found in the current directory, showing packages from packagist.org');
$installedRepo = $platformRepo;
$packagist = new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO());
$packagist = new ComposerRepository(array('url' => 'http://packagist.org'), $this->getIO(), Factory::createConfig());
$repos = new CompositeRepository(array($installedRepo, $packagist));
}
@ -78,7 +79,15 @@ EOT
$this->printMeta($input, $output, $package, $installedRepo, $repos);
$this->printLinks($input, $output, $package, 'requires');
$this->printLinks($input, $output, $package, 'recommends');
$this->printLinks($input, $output, $package, 'devRequires', 'requires (dev)');
if ($package->getSuggests()) {
$output->writeln("\n<info>suggests</info>");
foreach ($package->getSuggests() as $suggested => $reason) {
$output->writeln($suggested . ' <comment>' . $reason . '</comment>');
}
}
$this->printLinks($input, $output, $package, 'provides');
$this->printLinks($input, $output, $package, 'conflicts');
$this->printLinks($input, $output, $package, 'replaces');
return;
}
@ -209,10 +218,11 @@ EOT
*
* @param string $linkType
*/
protected function printLinks(InputInterface $input, OutputInterface $output, PackageInterface $package, $linkType)
protected function printLinks(InputInterface $input, OutputInterface $output, PackageInterface $package, $linkType, $title = null)
{
$title = $title ?: $linkType;
if ($links = $package->{'get'.ucfirst($linkType)}()) {
$output->writeln("\n<info>" . $linkType . "</info>");
$output->writeln("\n<info>" . $title . "</info>");
foreach ($links as $link) {
$output->writeln($link->getTarget() . ' <comment>' . $link->getPrettyConstraint() . '</comment>');

View File

@ -81,10 +81,10 @@ class Compiler
$this->addFile($phar, $file);
}
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/ClassLoader.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload_classmap.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_classmap.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/ClassLoader.php'));
$this->addComposerBin($phar);
// Stubs

View File

@ -67,6 +67,10 @@ class Application extends BaseApplication
$this->registerCommands();
$this->io = new ConsoleIO($input, $output, $this->getHelperSet());
if (version_compare(PHP_VERSION, '5.3.2', '<')) {
$output->writeln('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.</warning>');
}
return parent::doRun($input, $output);
}

View File

@ -69,6 +69,8 @@ class DefaultPolicy implements PolicyInterface
$literals = $this->pruneToBestVersion($literals);
$literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
$literals = $this->pruneRemoteAliases($literals);
}
$selected = call_user_func_array('array_merge', $packages);
@ -239,4 +241,38 @@ class DefaultPolicy implements PolicyInterface
return $selected;
}
/**
* Assumes that locally aliased (in root package requires) packages take priority over branch-alias ones
*
* If no package is a local alias, nothing happens
*/
protected function pruneRemoteAliases(array $literals)
{
$hasLocalAlias = false;
foreach ($literals as $literal) {
$package = $literal->getPackage();
if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
$hasLocalAlias = true;
break;
}
}
if (!$hasLocalAlias) {
return $literals;
}
$selected = array();
foreach ($literals as $literal) {
$package = $literal->getPackage();
if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
$selected[] = $literal;
}
}
return $selected;
}
}

View File

@ -1615,7 +1615,7 @@ class Solver
$foundDisabled = false;
foreach ($problemRules as $problemRule) {
if ($problemRule->disabled()) {
if ($problemRule->isDisabled()) {
$foundDisabled = true;
break;
}

View File

@ -24,6 +24,7 @@ use Composer\Util\Filesystem;
class DownloadManager
{
private $preferSource = false;
private $filesystem;
private $downloaders = array();
/**
@ -31,9 +32,10 @@ class DownloadManager
*
* @param Boolean $preferSource prefer downloading from source
*/
public function __construct($preferSource = false)
public function __construct($preferSource = false, Filesystem $filesystem = null)
{
$this->preferSource = $preferSource;
$this->filesystem = $filesystem ?: new Filesystem();
}
/**
@ -135,8 +137,7 @@ class DownloadManager
throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
}
$fs = new Filesystem();
$fs->ensureDirectoryExists($targetDir);
$this->filesystem->ensureDirectoryExists($targetDir);
$downloader = $this->getDownloaderForInstalledPackage($package);
$downloader->download($package, $targetDir);

View File

@ -26,7 +26,7 @@ class GitDownloader extends VcsDownloader
public function doDownload(PackageInterface $package, $path)
{
$ref = $package->getSourceReference();
$command = 'git clone %s %s && cd %2$s && git checkout %3$s && git reset --hard %3$s';
$command = 'git clone %s %s && cd %2$s && git checkout %3$s && git reset --hard %3$s && git remote add composer %1$s';
$this->io->write(" Cloning ".$package->getSourceReference());
$commandCallable = function($url) use ($ref, $path, $command) {
@ -44,14 +44,16 @@ class GitDownloader extends VcsDownloader
{
$ref = $target->getSourceReference();
$this->io->write(" Checking out ".$target->getSourceReference());
$command = 'cd %s && git remote set-url origin %s && git fetch origin && git fetch --tags origin && git checkout %3$s && git reset --hard %3$s';
$command = 'cd %s && git remote set-url composer %s && git fetch composer && git fetch --tags composer && git checkout %3$s && git reset --hard %3$s';
// TODO: BC for the composer remote that didn't exist, to be remove after May 18th.
$this->process->execute(sprintf('cd %s && git remote add composer %s', escapeshellarg($path), escapeshellarg($initial->getSourceUrl())), $ignoredOutput);
$commandCallable = function($url) use ($ref, $path, $command) {
return sprintf($command, escapeshellarg($path), escapeshellarg($url), escapeshellarg($ref));
};
$this->runCommand($commandCallable, $target->getSourceUrl());
$this->setPushUrl($target, $path);
}
/**
@ -59,7 +61,7 @@ class GitDownloader extends VcsDownloader
*/
protected function enforceCleanDirectory($path)
{
$command = sprintf('cd %s && git status --porcelain', escapeshellarg($path));
$command = sprintf('cd %s && git status --porcelain --untracked-files=no', escapeshellarg($path));
if (0 !== $this->process->execute($command, $output)) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
}

View File

@ -38,6 +38,14 @@ class Factory
}
}
// Protect directory against web access
if (!file_exists($home . '/.htaccess')) {
if (!is_dir($home)) {
@mkdir($home, 0777, true);
}
@file_put_contents($home . '/.htaccess', 'Deny from all');
}
$config = new Config();
$file = new JsonFile($home.'/config.json');
@ -84,7 +92,7 @@ class Factory
}
// Configuration defaults
$config = $this->createConfig();
$config = static::createConfig();
$config->merge($localConfig);
$vendorDir = $config->get('vendor-dir');
@ -151,8 +159,25 @@ class Factory
protected function addLocalRepository(RepositoryManager $rm, $vendorDir)
{
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
$rm->setLocalDevRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed_dev.json')));
// TODO BC feature, remove after May 30th
if (file_exists($vendorDir.'/.composer/installed.json')) {
if (!is_dir($vendorDir.'/composer')) { mkdir($vendorDir.'/composer/', 0777, true); }
rename($vendorDir.'/.composer/installed.json', $vendorDir.'/composer/installed.json');
}
if (file_exists($vendorDir.'/.composer/installed_dev.json')) {
if (!is_dir($vendorDir.'/composer')) { mkdir($vendorDir.'/composer/', 0777, true); }
rename($vendorDir.'/.composer/installed_dev.json', $vendorDir.'/composer/installed_dev.json');
}
if (file_exists($vendorDir.'/installed.json')) {
if (!is_dir($vendorDir.'/composer')) { mkdir($vendorDir.'/composer/', 0777, true); }
rename($vendorDir.'/installed.json', $vendorDir.'/composer/installed.json');
}
if (file_exists($vendorDir.'/installed_dev.json')) {
if (!is_dir($vendorDir.'/composer')) { mkdir($vendorDir.'/composer/', 0777, true); }
rename($vendorDir.'/installed_dev.json', $vendorDir.'/composer/installed_dev.json');
}
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json')));
$rm->setLocalDevRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed_dev.json')));
}
protected function addPackagistRepository(array $localConfig)

View File

@ -55,6 +55,14 @@ class ConsoleIO implements IOInterface
return $this->input->isInteractive();
}
/**
* {@inheritDoc}
*/
public function isDecorated()
{
return $this->output->isDecorated();
}
/**
* {@inheritDoc}
*/

View File

@ -33,6 +33,13 @@ interface IOInterface
*/
function isVerbose();
/**
* Is this output decorated?
*
* @return Boolean
*/
function isDecorated();
/**
* Writes a message to the output.
*

View File

@ -35,6 +35,14 @@ class NullIO implements IOInterface
return false;
}
/**
* {@inheritDoc}
*/
public function isDecorated()
{
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -27,6 +27,7 @@ use Composer\Package\Link;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Package\Locker;
use Composer\Package\PackageInterface;
use Composer\Repository\ArrayRepository;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
@ -76,6 +77,11 @@ class Installer
*/
protected $eventDispatcher;
/**
* @var AutoloadGenerator
*/
protected $autoloadGenerator;
protected $preferSource = false;
protected $devMode = false;
protected $dryRun = false;
@ -102,8 +108,9 @@ class Installer
* @param Locker $locker
* @param InstallationManager $installationManager
* @param EventDispatcher $eventDispatcher
* @param AutoloadGenerator $autoloadGenerator
*/
public function __construct(IOInterface $io, PackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher)
public function __construct(IOInterface $io, PackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher, AutoloadGenerator $autoloadGenerator)
{
$this->io = $io;
$this->package = $package;
@ -112,6 +119,7 @@ class Installer
$this->locker = $locker;
$this->installationManager = $installationManager;
$this->eventDispatcher = $eventDispatcher;
$this->autoloadGenerator = $autoloadGenerator;
}
/**
@ -128,7 +136,13 @@ class Installer
}
// create installed repo, this contains all local packages + platform packages (php & extensions)
$repos = array_merge($this->repositoryManager->getLocalRepositories(), array(new PlatformRepository()));
$repos = array_merge(
$this->repositoryManager->getLocalRepositories(),
array(
new ArrayRepository(array($this->package)),
new PlatformRepository(),
)
);
$installedRepo = new CompositeRepository($repos);
if ($this->additionalInstalledRepository) {
$installedRepo->addRepository($this->additionalInstalledRepository);
@ -152,10 +166,12 @@ class Installer
}
}
// dump suggestions
// output suggestions
foreach ($this->suggestedPackages as $suggestion) {
if (!$installedRepo->findPackages($suggestion['target'])) {
$this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')');
}
}
if (!$this->dryRun) {
// write lock
@ -172,9 +188,8 @@ class Installer
// write autoloader
$this->io->write('<info>Generating autoload files</info>');
$generator = new AutoloadGenerator;
$localRepos = new CompositeRepository($this->repositoryManager->getLocalRepositories());
$generator->dump($localRepos, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer');
$this->autoloadGenerator->dump($localRepos, $this->package, $this->installationManager, $this->installationManager->getVendorPath() . '/composer', true);
// dispatch post event
$eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
@ -186,6 +201,11 @@ class Installer
protected function doInstall($localRepo, $installedRepo, $aliases, $devMode = false)
{
// initialize locker to create aliased packages
if (!$this->update && $this->locker->isLocked($devMode)) {
$lockedPackages = $this->locker->getLockedPackages($devMode);
}
// creating repository pool
$pool = new Pool;
$pool->addRepository($installedRepo);
@ -196,6 +216,10 @@ class Installer
// creating requirements request
$installFromLock = false;
$request = new Request($pool);
$constraint = new VersionConstraint('=', $this->package->getVersion());
$request->install($this->package->getName(), $constraint);
if ($this->update) {
$this->io->write('<info>Updating '.($devMode ? 'dev ': '').'dependencies</info>');
@ -214,7 +238,7 @@ class Installer
$this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>');
}
foreach ($this->locker->getLockedPackages($devMode) as $package) {
foreach ($lockedPackages as $package) {
$version = $package->getVersion();
foreach ($aliases as $alias) {
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
@ -378,14 +402,16 @@ class Installer
foreach ($this->repositoryManager->findPackages($alias['package'], $alias['version']) as $package) {
$package->setAlias($alias['alias_normalized']);
$package->setPrettyAlias($alias['alias']);
$package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$aliasPackage->setRootPackageAlias(true);
}
foreach ($this->repositoryManager->getLocalRepositories() as $repo) {
foreach ($repo->findPackages($alias['package'], $alias['version']) as $package) {
$package->setAlias($alias['alias_normalized']);
$package->setPrettyAlias($alias['alias']);
$package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$package->getRepository()->removePackage($package);
$aliasPackage->setRootPackageAlias(true);
}
}
}
@ -399,11 +425,13 @@ class Installer
* @param IOInterface $io
* @param Composer $composer
* @param EventDispatcher $eventDispatcher
* @param AutoloadGenerator $autoloadGenerator
* @return Installer
*/
static public function create(IOInterface $io, Composer $composer, EventDispatcher $eventDispatcher = null)
static public function create(IOInterface $io, Composer $composer, EventDispatcher $eventDispatcher = null, AutoloadGenerator $autoloadGenerator = null)
{
$eventDispatcher = $eventDispatcher ?: new EventDispatcher($composer, $io);
$autoloadGenerator = $autoloadGenerator ?: new AutoloadGenerator;
return new static(
$io,
@ -412,7 +440,8 @@ class Installer
$composer->getRepositoryManager(),
$composer->getLocker(),
$composer->getInstallationManager(),
$eventDispatcher
$eventDispatcher,
$autoloadGenerator
);
}

View File

@ -16,6 +16,7 @@ use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\NotifiableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
@ -96,12 +97,12 @@ class InstallationManager
/**
* Checks whether provided package is installed in one of the registered installers.
*
* @param RepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance
*
* @return Boolean
*/
public function isPackageInstalled(RepositoryInterface $repo, PackageInterface $package)
public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
{
return $this->getInstaller($package->getType())->isInstalled($repo, $package);
}
@ -126,11 +127,7 @@ class InstallationManager
*/
public function install(RepositoryInterface $repo, InstallOperation $operation)
{
$package = $operation->getPackage();
if ($package instanceof AliasPackage) {
$package = $package->getAliasOf();
$package->setInstalledAsAlias(true);
}
$package = $this->antiAlias($operation->getPackage());
$installer = $this->getInstaller($package->getType());
$installer->install($repo, $package);
$this->notifyInstall($package);
@ -144,15 +141,8 @@ class InstallationManager
*/
public function update(RepositoryInterface $repo, UpdateOperation $operation)
{
$initial = $operation->getInitialPackage();
if ($initial instanceof AliasPackage) {
$initial = $initial->getAliasOf();
}
$target = $operation->getTargetPackage();
if ($target instanceof AliasPackage) {
$target = $target->getAliasOf();
$target->setInstalledAsAlias(true);
}
$initial = $this->antiAlias($operation->getInitialPackage());
$target = $this->antiAlias($operation->getTargetPackage());
$initialType = $initial->getType();
$targetType = $target->getType();
@ -175,10 +165,7 @@ class InstallationManager
*/
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
{
$package = $operation->getPackage();
if ($package instanceof AliasPackage) {
$package = $package->getAliasOf();
}
$package = $this->antiAlias($operation->getPackage());
$installer = $this->getInstaller($package->getType());
$installer->uninstall($repo, $package);
}
@ -210,10 +197,23 @@ class InstallationManager
return getcwd().DIRECTORY_SEPARATOR.$this->vendorPath;
}
protected function notifyInstall(PackageInterface $package)
private function notifyInstall(PackageInterface $package)
{
if ($package->getRepository() instanceof NotifiableRepositoryInterface) {
$package->getRepository()->notifyInstall($package);
}
}
private function antiAlias(PackageInterface $package)
{
if ($package instanceof AliasPackage) {
$alias = $package;
$package = $package->getAliasOf();
$package->setInstalledAsAlias(true);
$package->setAlias($alias->getVersion());
$package->setPrettyAlias($alias->getPrettyVersion());
}
return $package;
}
}

View File

@ -15,7 +15,7 @@ namespace Composer\Installer;
use Composer\IO\IOInterface;
use Composer\Autoload\AutoloadGenerator;
use Composer\Downloader\DownloadManager;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface;
@ -35,7 +35,7 @@ class InstallerInstaller extends LibraryInstaller
* @param DownloadManager $dm download manager
* @param IOInterface $io io instance
* @param InstallationManager $im installation manager
* @param array $localRepositories array of WritableRepositoryInterface
* @param array $localRepositories array of InstalledRepositoryInterface
*/
public function __construct($vendorDir, $binDir, DownloadManager $dm, IOInterface $io, InstallationManager $im, array $localRepositories)
{
@ -54,7 +54,7 @@ class InstallerInstaller extends LibraryInstaller
/**
* {@inheritDoc}
*/
public function install(WritableRepositoryInterface $repo, PackageInterface $package)
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$extra = $package->getExtra();
if (empty($extra['class'])) {
@ -68,7 +68,7 @@ class InstallerInstaller extends LibraryInstaller
/**
* {@inheritDoc}
*/
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
$extra = $target->getExtra();
if (empty($extra['class'])) {

View File

@ -14,7 +14,7 @@ namespace Composer\Installer;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
/**
* Interface for the package installation manager.
@ -35,39 +35,39 @@ interface InstallerInterface
/**
* Checks that provided package is installed.
*
* @param WritableRepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance
*
* @return Boolean
*/
function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package);
function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package);
/**
* Installs specific package.
*
* @param WritableRepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance
*/
function install(WritableRepositoryInterface $repo, PackageInterface $package);
function install(InstalledRepositoryInterface $repo, PackageInterface $package);
/**
* Updates specific package.
*
* @param WritableRepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $initial already installed package version
* @param PackageInterface $target updated version
*
* @throws InvalidArgumentException if $from package is not installed
*/
function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target);
function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target);
/**
* Uninstalls specific package.
*
* @param WritableRepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance
*/
function uninstall(WritableRepositoryInterface $repo, PackageInterface $package);
function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package);
/**
* Returns the installation path of a package

View File

@ -14,7 +14,7 @@ namespace Composer\Installer;
use Composer\IO\IOInterface;
use Composer\Downloader\DownloadManager;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface;
use Composer\Util\Filesystem;
@ -65,7 +65,7 @@ class LibraryInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package)
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
{
return $repo->hasPackage($package) && is_readable($this->getInstallPath($package));
}
@ -73,7 +73,7 @@ class LibraryInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function install(WritableRepositoryInterface $repo, PackageInterface $package)
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$this->initializeVendorDir();
$downloadPath = $this->getInstallPath($package);
@ -93,7 +93,7 @@ class LibraryInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
if (!$repo->hasPackage($initial)) {
throw new \InvalidArgumentException('Package is not installed: '.$initial);
@ -114,7 +114,7 @@ class LibraryInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package)
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
if (!$repo->hasPackage($package)) {
// TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125)
@ -152,7 +152,7 @@ class LibraryInstaller implements InstallerInterface
// likely leftover from a previous install, make sure
// that the target is still executable in case this
// is a fresh install of the vendor.
chmod($link, 0755);
chmod($link, 0777 & ~umask());
}
$this->io->write('Skipped installation of '.$bin.' for package '.$package->getName().', name conflicts with an existing file');
continue;
@ -163,21 +163,24 @@ class LibraryInstaller implements InstallerInterface
// add unixy support for cygwin and similar environments
if ('.bat' !== substr($bin, -4)) {
file_put_contents($link, $this->generateUnixyProxyCode($bin, $link));
chmod($link, 0755);
chmod($link, 0777 & ~umask());
$link .= '.bat';
}
file_put_contents($link, $this->generateWindowsProxyCode($bin, $link));
} else {
$cwd = getcwd();
try {
// under linux symlinks are not always supported for example
// when using it in smbfs mounted folder
symlink($bin, $link);
$relativeBin = $this->filesystem->findShortestPath($link, $bin);
chdir(dirname($link));
symlink($relativeBin, $link);
} catch (\ErrorException $e) {
file_put_contents($link, $this->generateUnixyProxyCode($bin, $link));
}
chdir($cwd);
}
chmod($link, 0755);
chmod($link, 0777 & ~umask());
}
}
@ -186,7 +189,7 @@ class LibraryInstaller implements InstallerInterface
if (!$package->getBinaries()) {
return;
}
foreach ($package->getBinaries() as $bin => $os) {
foreach ($package->getBinaries() as $bin) {
$link = $this->binDir.'/'.basename($bin);
if (!file_exists($link)) {
continue;

View File

@ -12,7 +12,7 @@
namespace Composer\Installer;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
/**
@ -33,7 +33,7 @@ class MetapackageInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package)
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
{
return $repo->hasPackage($package);
}
@ -41,7 +41,7 @@ class MetapackageInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function install(WritableRepositoryInterface $repo, PackageInterface $package)
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$repo->addPackage(clone $package);
}
@ -49,7 +49,7 @@ class MetapackageInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
if (!$repo->hasPackage($initial)) {
throw new \InvalidArgumentException('Package is not installed: '.$initial);
@ -62,7 +62,7 @@ class MetapackageInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package)
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
if (!$repo->hasPackage($package)) {
// TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125)

View File

@ -15,6 +15,7 @@ namespace Composer\Installer;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface;
use Composer\Downloader\DownloadManager;
use Composer\Repository\InstalledRepositoryInterface;
/**
* Project Installer is used to install a single package into a directory as
@ -45,23 +46,17 @@ class ProjectInstaller implements InstallerInterface
}
/**
* Checks that provided package is installed.
*
* @param PackageInterface $package package instance
*
* @return Boolean
* {@inheritDoc}
*/
public function isInstalled(PackageInterface $package)
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
{
return false;
}
/**
* Installs specific package.
*
* @param PackageInterface $package package instance
* {@inheritDoc}
*/
public function install(PackageInterface $package)
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$installPath = $this->installPath;
if (file_exists($installPath)) {
@ -75,24 +70,17 @@ class ProjectInstaller implements InstallerInterface
}
/**
* Updates specific package.
*
* @param PackageInterface $initial already installed package version
* @param PackageInterface $target updated version
*
* @throws InvalidArgumentException if $from package is not installed
* {@inheritDoc}
*/
public function update(PackageInterface $initial, PackageInterface $target)
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
throw new \InvalidArgumentException("not supported");
}
/**
* Uninstalls specific package.
*
* @param PackageInterface $package package instance
* {@inheritDoc}
*/
public function uninstall(PackageInterface $package)
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
throw new \InvalidArgumentException("not supported");
}

View File

@ -237,7 +237,7 @@ class JsonFile
}
} else {
// Collapse empty {} and []
$result = rtrim($result);
$result = rtrim($result)."\n\n".$indentStr;
}
}

View File

@ -27,6 +27,7 @@ class AliasPackage extends BasePackage
protected $prettyVersion;
protected $dev;
protected $aliasOf;
protected $rootPackageAlias = false;
protected $requires;
protected $conflicts;
@ -146,6 +147,27 @@ class AliasPackage extends BasePackage
return $this->devRequires;
}
/**
* Stores whether this is an alias created by an aliasing in the requirements of the root package or not
*
* Use by the policy for sorting manually aliased packages first, see #576
*
* @param Boolean $value
*/
public function setRootPackageAlias($value)
{
return $this->rootPackageAlias = $value;
}
/**
* @see setRootPackageAlias
* @return Boolean
*/
public function isRootPackageAlias()
{
return $this->rootPackageAlias;
}
/**
* {@inheritDoc}
*/
@ -222,6 +244,14 @@ class AliasPackage extends BasePackage
{
return $this->aliasOf->getScripts();
}
public function setAliases(array $aliases)
{
return $this->aliasOf->setAliases($aliases);
}
public function getAliases()
{
return $this->aliasOf->getAliases();
}
public function getLicense()
{
return $this->aliasOf->getLicense();

View File

@ -58,7 +58,10 @@ class ArrayLoader
$package->setExtra($config['extra']);
}
if (isset($config['bin']) && is_array($config['bin'])) {
if (isset($config['bin'])) {
if (!is_array($config['bin'])) {
throw new \UnexpectedValueException('Package '.$config['name'].'\'s bin key should be an array, '.gettype($config['bin']).' given.');
}
foreach ($config['bin'] as $key => $bin) {
$config['bin'][$key]= ltrim($bin, '/');
}
@ -166,6 +169,11 @@ class ArrayLoader
}
if (isset($config['suggest']) && is_array($config['suggest'])) {
foreach ($config['suggest'] as $target => $reason) {
if ('self.version' === trim($reason)) {
$config['suggest'][$target] = $package->getPrettyVersion();
}
}
$package->setSuggests($config['suggest']);
}

View File

@ -14,6 +14,8 @@ namespace Composer\Package\Loader;
use Composer\Package\Version\VersionParser;
use Composer\Repository\RepositoryManager;
use Composer\Util\ProcessExecutor;
use Composer\Package\AliasPackage;
/**
* ArrayLoader built for the sole purpose of loading the root package
@ -25,10 +27,12 @@ use Composer\Repository\RepositoryManager;
class RootPackageLoader extends ArrayLoader
{
private $manager;
private $process;
public function __construct(RepositoryManager $manager, VersionParser $parser = null)
public function __construct(RepositoryManager $manager, VersionParser $parser = null, ProcessExecutor $process = null)
{
$this->manager = $manager;
$this->process = $process ?: new ProcessExecutor();
parent::__construct($parser);
}
@ -38,7 +42,20 @@ class RootPackageLoader extends ArrayLoader
$config['name'] = '__root__';
}
if (!isset($config['version'])) {
$config['version'] = '1.0.0';
$version = '1.0.0';
// try to fetch current version from git branch
if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) {
foreach ($this->process->splitLines($output) as $branch) {
if ($branch && preg_match('{^(?:\* ) *(?:[^/ ]+?/)?(\S+) *[a-f0-9]+ .*$}', $branch, $match)) {
$version = 'dev-'.$match[1];
}
}
}
$config['version'] = $version;
} else {
$version = $config['version'];
}
$package = parent::load($config);
@ -76,6 +93,16 @@ class RootPackageLoader extends ArrayLoader
$package->setRepositories($config['repositories']);
}
if (isset($config['extra']['branch-alias'][$version])
&& substr($config['extra']['branch-alias'][$version], -4) === '-dev'
) {
$targetBranch = $config['extra']['branch-alias'][$version];
$normalized = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
$version = preg_replace('{(\.9{7})+}', '.x', $normalized);
return new AliasPackage($package, $normalized, $version);
}
return $package;
}
}

View File

@ -90,12 +90,22 @@ class Locker
foreach ($lockedPackages as $info) {
$resolvedVersion = !empty($info['alias']) ? $info['alias'] : $info['version'];
// try to find the package in the local repo (best match)
$package = $repo->findPackage($info['package'], $resolvedVersion);
// try to find the package in any repo
if (!$package) {
$package = $this->repositoryManager->findPackage($info['package'], $resolvedVersion);
}
// try to find the package in any repo (second pass without alias + rebuild alias since it disappeared)
if (!$package && !empty($info['alias'])) {
$package = $this->repositoryManager->findPackage($info['package'], $info['version']);
if ($package && !empty($info['alias'])) {
$package = new AliasPackage($package, $info['alias'], $info['alias']);
if ($package) {
$alias = new AliasPackage($package, $info['alias'], $info['alias']);
$package->getRepository()->addPackage($alias);
$package = $alias;
}
}

View File

@ -25,6 +25,13 @@ class ArrayRepository implements RepositoryInterface
{
protected $packages;
public function __construct(array $packages = array())
{
foreach ($packages as $package) {
$this->addPackage($package);
}
}
/**
* {@inheritDoc}
*/

View File

@ -40,7 +40,7 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
$repoConfig['url'] = 'http://'.$repoConfig['url'];
}
$repoConfig['url'] = rtrim($repoConfig['url'], '/');
if (function_exists('filter_var') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
if (function_exists('filter_var') && version_compare(PHP_VERSION, '5.3.3', '>=') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
}
@ -70,7 +70,7 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($params),
'content' => http_build_query($params, '', '&'),
'timeout' => 3,
)
);

View File

@ -21,6 +21,6 @@ use Composer\Package\PackageInterface;
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
interface InstalledRepositoryInterface
interface InstalledRepositoryInterface extends WritableRepositoryInterface
{
}

View File

@ -28,6 +28,7 @@ class PearRepository extends ArrayRepository
private static $channelNames = array();
private $url;
private $baseUrl;
private $channel;
private $io;
private $rfs;
@ -38,7 +39,7 @@ class PearRepository extends ArrayRepository
$repoConfig['url'] = 'http://'.$repoConfig['url'];
}
if (function_exists('filter_var') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
if (function_exists('filter_var') && version_compare(PHP_VERSION, '5.3.3', '>=') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$repoConfig['url']);
}
@ -68,8 +69,13 @@ class PearRepository extends ArrayRepository
$loader = new ArrayLoader();
foreach ($packages as $data) {
foreach ($data['versions'] as $rev) {
if (strpos($rev['name'], 'pear-'.$this->channel) !== 0) {
$rev['name'] = 'pear-'.$this->channel.'/'.$rev['name'];
}
$this->addPackage($loader->load($rev));
if ($this->io->isVerbose()) {
$this->io->write('Loaded '.$rev['name'].' '.$rev['version']);
}
}
}
@ -87,26 +93,31 @@ class PearRepository extends ArrayRepository
$this->channel = $channelXML->getElementsByTagName("suggestedalias")->item(0)->nodeValue
?: $channelXML->getElementsByTagName("name")->item(0)->nodeValue;
}
if (!$this->baseUrl) {
$this->baseUrl = $channelXML->getElementsByTagName("baseurl")->item(0)->nodeValue
? trim($channelXML->getElementsByTagName("baseurl")->item(0)->nodeValue, '/')
: $this->url . '/rest';
}
self::$channelNames[$channelXML->getElementsByTagName("name")->item(0)->nodeValue] = $this->channel;
}
protected function fetchFromServer()
{
$categoryXML = $this->requestXml($this->url . "/rest/c/categories.xml");
$categoryXML = $this->requestXml($this->baseUrl . "/c/categories.xml");
$categories = $categoryXML->getElementsByTagName("c");
foreach ($categories as $category) {
$link = '/' . ltrim($category->getAttribute("xlink:href"), '/');
$link = $this->baseUrl . '/c/' . str_replace(' ', '+', $category->nodeValue);
try {
$packagesLink = str_replace("info.xml", "packagesinfo.xml", $link);
$this->fetchPear2Packages($this->url . $packagesLink);
$packagesLink = $link . "/packagesinfo.xml";
$this->fetchPear2Packages($packagesLink);
} catch (TransportException $e) {
if (false === strpos($e->getMessage(), '404')) {
throw $e;
}
$categoryLink = str_replace("info.xml", "packages.xml", $link);
$this->fetchPearPackages($this->url . $categoryLink);
$categoryLink = $link . "/packages.xml";
$this->fetchPearPackages($categoryLink);
}
}
@ -126,8 +137,7 @@ class PearRepository extends ArrayRepository
$packageName = $package->nodeValue;
$fullName = 'pear-'.$this->channel.'/'.$packageName;
$packageLink = $package->getAttribute('xlink:href');
$releaseLink = $this->url . str_replace("/rest/p/", "/rest/r/", $packageLink);
$releaseLink = $this->baseUrl . "/r/" . $packageName;
$allReleasesLink = $releaseLink . "/allreleases2.xml";
try {
@ -357,7 +367,7 @@ class PearRepository extends ArrayRepository
throw new \UnexpectedValueException('The PEAR channel at '.$url.' did not respond.');
}
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->loadXML($content);
$dom->loadXML($content, LIBXML_NOERROR);
return $dom;
}

View File

@ -27,20 +27,14 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, IOInterface $io)
{
preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $io);
}
/**
* {@inheritDoc}
*/
public function initialize()
{
preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
}
/**

View File

@ -28,11 +28,6 @@ class GitDriver extends VcsDriver
protected $repoDir;
protected $infoCache = array();
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
{
parent::__construct($url, $io, $process);
}
/**
* {@inheritDoc}
*/
@ -41,11 +36,13 @@ class GitDriver extends VcsDriver
if (static::isLocalUrl($this->url)) {
$this->repoDir = str_replace('file://', '', $this->url);
} else {
$this->repoDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
$this->repoDir = $this->config->get('home') . '/cache.git/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
// update the repo if it is a valid git repository
if (is_dir($this->repoDir) && 0 === $this->process->execute('git remote', $output, $this->repoDir)) {
$this->process->execute('git remote update --prune origin', $output, $this->repoDir);
if (0 !== $this->process->execute('git remote update --prune origin', $output, $this->repoDir)) {
$this->io->write('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
}
} else {
// clean up directory and do a fresh clone into it
$fs = new Filesystem();

View File

@ -38,28 +38,15 @@ class GitHubDriver extends VcsDriver
*/
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);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $io, $process, $remoteFilesystem);
}
/**
* {@inheritDoc}
*/
public function initialize()
{
preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
$this->fetchRootIdentifier();
}
@ -248,6 +235,7 @@ class GitHubDriver extends VcsDriver
$this->gitDriver = new GitDriver(
$this->generateSshUrl(),
$this->io,
$this->config,
$this->process,
$this->remoteFilesystem
);

View File

@ -27,20 +27,14 @@ class HgBitbucketDriver extends VcsDriver
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, IOInterface $io)
{
preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $io);
}
/**
* {@inheritDoc}
*/
public function initialize()
{
preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
}
/**

View File

@ -26,24 +26,21 @@ class HgDriver extends VcsDriver
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
{
$this->tmpDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $url) . '/';
parent::__construct($url, $io, $process);
}
/**
* {@inheritDoc}
*/
public function initialize()
{
$url = escapeshellarg($this->url);
$tmpDir = escapeshellarg($this->tmpDir);
$this->tmpDir = $this->config->get('home') . '/cache.hg/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/';
if (is_dir($this->tmpDir)) {
$this->process->execute(sprintf('cd %s && hg pull -u', $tmpDir), $output);
$this->process->execute(sprintf('cd %s && hg pull -u', escapeshellarg($this->tmpDir)), $output);
} else {
$this->process->execute(sprintf('cd %s && hg clone %s %s', escapeshellarg(sys_get_temp_dir()), $url, $tmpDir), $output);
$dir = dirname($this->tmpDir);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$this->process->execute(sprintf('cd %s && hg clone %s %s', escapeshellarg($dir), escapeshellarg($this->url), escapeshellarg($this->tmpDir)), $output);
}
$this->getTags();

View File

@ -33,25 +33,7 @@ class SvnDriver extends VcsDriver
/**
* @var \Composer\Util\Svn
*/
protected $util;
/**
* @param string $url
* @param IOInterface $io
* @param ProcessExecutor $process
*
* @return $this
*/
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
{
$url = self::normalizeUrl($url);
parent::__construct($this->baseUrl = rtrim($url, '/'), $io, $process);
if (false !== ($pos = strrpos($url, '/trunk'))) {
$this->baseUrl = substr($url, 0, $pos);
}
$this->util = new SvnUtil($this->baseUrl, $io, $this->process);
}
private $util;
/**
* Execute an SVN command and try to fix up the process with credentials
@ -64,6 +46,10 @@ class SvnDriver extends VcsDriver
*/
protected function execute($command, $url)
{
if (null === $this->util) {
$this->util = new SvnUtil($this->baseUrl, $this->io, $this->process);
}
try {
return $this->util->execute($command, $url);
} catch (\RuntimeException $e) {
@ -78,6 +64,12 @@ class SvnDriver extends VcsDriver
*/
public function initialize()
{
$this->url = $this->baseUrl = rtrim(self::normalizeUrl($this->url), '/');
if (false !== ($pos = strrpos($this->url, '/trunk'))) {
$this->baseUrl = substr($this->url, 0, $pos);
}
$this->getBranches();
$this->getTags();
}

View File

@ -13,6 +13,7 @@
namespace Composer\Repository\Vcs;
use Composer\Downloader\TransportException;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\ProcessExecutor;
use Composer\Util\RemoteFilesystem;
@ -26,6 +27,7 @@ abstract class VcsDriver implements VcsDriverInterface
{
protected $url;
protected $io;
protected $config;
protected $process;
protected $remoteFilesystem;
@ -34,13 +36,15 @@ abstract class VcsDriver implements VcsDriverInterface
*
* @param string $url The URL
* @param IOInterface $io The IO instance
* @param Config $config The composer configuration
* @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, $remoteFilesystem = null)
final public function __construct($url, IOInterface $io, Config $config, ProcessExecutor $process = null, $remoteFilesystem = null)
{
$this->url = $url;
$this->io = $io;
$this->config = $config;
$this->process = $process ?: new ProcessExecutor;
$this->remoteFilesystem = $remoteFilesystem ?: new RemoteFilesystem($io);
}
@ -58,7 +62,6 @@ abstract class VcsDriver implements VcsDriverInterface
return false;
}
/**
* Get the https or http protocol depending on SSL support.
*

View File

@ -30,6 +30,7 @@ class VcsRepository extends ArrayRepository
protected $packageName;
protected $verbose;
protected $io;
protected $config;
protected $versionParser;
protected $type;
@ -48,20 +49,21 @@ class VcsRepository extends ArrayRepository
$this->io = $io;
$this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
$this->verbose = $io->isVerbose();
$this->config = $config;
}
public function getDriver()
{
if (isset($this->drivers[$this->type])) {
$class = $this->drivers[$this->type];
$driver = new $class($this->url, $this->io);
$driver = new $class($this->url, $this->io, $this->config);
$driver->initialize();
return $driver;
}
foreach ($this->drivers as $driver) {
if ($driver::supports($this->io, $this->url)) {
$driver = new $driver($this->url, $this->io);
$driver = new $driver($this->url, $this->io, $this->config);
$driver->initialize();
return $driver;
}
@ -69,7 +71,7 @@ class VcsRepository extends ArrayRepository
foreach ($this->drivers as $driver) {
if ($driver::supports($this->io, $this->url, true)) {
$driver = new $driver($this->url, $this->io);
$driver = new $driver($this->url, $this->io, $this->config);
$driver->initialize();
return $driver;
}

View File

@ -46,7 +46,11 @@ final class StreamContextFactory
}
// http(s):// is not supported in proxy
$proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);
if ('http://' == substr($proxy, 0, 7)) {
$proxy = 'tcp://' . rtrim(substr($proxy, 7), '/') . (parse_url($proxy, PHP_URL_PORT) ? '' : ':80');
} else if ('https://' == substr($proxy, 0, 8)) {
$proxy = 'ssl://' . rtrim(substr($proxy, 8), '/') . (parse_url($proxy, PHP_URL_PORT) ? '' : ':443');
}
if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');

View File

@ -16,7 +16,7 @@ function includeIfExists($file) {
}
}
if ((!$loader = includeIfExists(__DIR__.'/../vendor/.composer/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../.composer/autoload.php'))) {
if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../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);

View File

@ -60,14 +60,14 @@ class AutoloadGeneratorTest extends TestCase
protected function tearDown()
{
if ($this->vendorDir === $this->workingDir) {
if (is_dir($this->workingDir.'/.composer')) {
$this->fs->removeDirectory($this->workingDir.'/.composer');
if (is_dir($this->workingDir.'/composer')) {
$this->fs->removeDirectory($this->workingDir.'/composer');
}
} elseif (is_dir($this->vendorDir)) {
$this->fs->removeDirectory($this->vendorDir);
}
if (is_dir($this->workingDir.'/.composersrc')) {
$this->fs->removeDirectory($this->workingDir.'/.composersrc');
if (is_dir($this->workingDir.'/composersrc')) {
$this->fs->removeDirectory($this->workingDir.'/composersrc');
}
chdir($this->dir);
@ -78,22 +78,22 @@ class AutoloadGeneratorTest extends TestCase
$package = new MemoryPackage('a', '1.0', '1.0');
$package->setAutoload(array(
'psr-0' => array('Main' => 'src/', 'Lala' => array('src/', 'lib/')),
'classmap' => array('.composersrc/'),
'classmap' => array('composersrc/'),
));
$this->repository->expects($this->once())
->method('getPackages')
->will($this->returnValue(array()));
if (!is_dir($this->vendorDir.'/.composer')) {
mkdir($this->vendorDir.'/.composer');
if (!is_dir($this->vendorDir.'/composer')) {
mkdir($this->vendorDir.'/composer');
}
$this->createClassFile($this->workingDir);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('main', $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('classmap', $this->vendorDir.'/.composer', 'classmap');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertAutoloadFiles('main', $this->vendorDir.'/composer');
$this->assertAutoloadFiles('classmap', $this->vendorDir.'/composer', 'classmap');
}
public function testVendorDirSameAsWorkingDir()
@ -103,22 +103,22 @@ class AutoloadGeneratorTest extends TestCase
$package = new MemoryPackage('a', '1.0', '1.0');
$package->setAutoload(array(
'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'),
'classmap' => array('.composersrc/'),
'classmap' => array('composersrc/'),
));
$this->repository->expects($this->once())
->method('getPackages')
->will($this->returnValue(array()));
if (!is_dir($this->vendorDir.'/.composer')) {
mkdir($this->vendorDir.'/.composer', 0777, true);
if (!is_dir($this->vendorDir.'/composer')) {
mkdir($this->vendorDir.'/composer', 0777, true);
}
$this->createClassFile($this->vendorDir);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('main3', $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('classmap3', $this->vendorDir.'/.composer', 'classmap');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertAutoloadFiles('main3', $this->vendorDir.'/composer');
$this->assertAutoloadFiles('classmap3', $this->vendorDir.'/composer', 'classmap');
}
public function testMainPackageAutoloadingAlternativeVendorDir()
@ -126,7 +126,7 @@ class AutoloadGeneratorTest extends TestCase
$package = new MemoryPackage('a', '1.0', '1.0');
$package->setAutoload(array(
'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'),
'classmap' => array('.composersrc/'),
'classmap' => array('composersrc/'),
));
$this->repository->expects($this->once())
@ -134,11 +134,27 @@ class AutoloadGeneratorTest extends TestCase
->will($this->returnValue(array()));
$this->vendorDir .= '/subdir';
mkdir($this->vendorDir.'/.composer', 0777, true);
mkdir($this->vendorDir.'/composer', 0777, true);
$this->createClassFile($this->workingDir);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('main2', $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('classmap2', $this->vendorDir.'/.composer', 'classmap');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertAutoloadFiles('main2', $this->vendorDir.'/composer');
$this->assertAutoloadFiles('classmap2', $this->vendorDir.'/composer', 'classmap');
}
public function testMainPackageAutoloadingWithTargetDir()
{
$package = new MemoryPackage('a', '1.0', '1.0');
$package->setAutoload(array(
'psr-0' => array('Main\\Foo' => '', 'Main\\Bar' => ''),
));
$package->setTargetDir('Main/Foo/');
$this->repository->expects($this->once())
->method('getPackages')
->will($this->returnValue(array()));
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertFileEquals(__DIR__.'/Fixtures/autoload_target_dir.php', $this->vendorDir.'/autoload.php');
}
public function testVendorsAutoloading()
@ -155,10 +171,10 @@ class AutoloadGeneratorTest extends TestCase
->method('getPackages')
->will($this->returnValue($packages));
mkdir($this->vendorDir.'/.composer', 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('vendors', $this->vendorDir.'/.composer');
$this->assertTrue(file_exists($this->vendorDir.'/.composer/autoload_classmap.php'), "ClassMap file needs to be generated, even if empty.");
mkdir($this->vendorDir.'/composer', 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertAutoloadFiles('vendors', $this->vendorDir.'/composer');
$this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated, even if empty.");
}
public function testVendorsClassMapAutoloading()
@ -175,7 +191,7 @@ class AutoloadGeneratorTest extends TestCase
->method('getPackages')
->will($this->returnValue($packages));
@mkdir($this->vendorDir.'/.composer', 0777, true);
@mkdir($this->vendorDir.'/composer', 0777, true);
mkdir($this->vendorDir.'/a/a/src', 0777, true);
mkdir($this->vendorDir.'/b/b/src', 0777, true);
mkdir($this->vendorDir.'/b/b/lib', 0777, true);
@ -183,17 +199,17 @@ class AutoloadGeneratorTest extends TestCase
file_put_contents($this->vendorDir.'/b/b/src/b.php', '<?php class ClassMapBar {}');
file_put_contents($this->vendorDir.'/b/b/lib/c.php', '<?php class ClassMapBaz {}');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertTrue(file_exists($this->vendorDir.'/.composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->assertEquals(
array(
'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
'ClassMapBar' => $this->workingDir.'/composer-test-autoload/b/b/src/b.php',
'ClassMapBaz' => $this->workingDir.'/composer-test-autoload/b/b/lib/c.php',
),
include ($this->vendorDir.'/.composer/autoload_classmap.php')
include ($this->vendorDir.'/composer/autoload_classmap.php')
);
$this->assertAutoloadFiles('classmap4', $this->vendorDir.'/.composer', 'classmap');
$this->assertAutoloadFiles('classmap4', $this->vendorDir.'/composer', 'classmap');
}
public function testClassMapAutoloadingEmptyDirAndExactFile()
@ -212,7 +228,7 @@ class AutoloadGeneratorTest extends TestCase
->method('getPackages')
->will($this->returnValue($packages));
@mkdir($this->vendorDir.'/.composer', 0777, true);
@mkdir($this->vendorDir.'/composer', 0777, true);
mkdir($this->vendorDir.'/a/a/src', 0777, true);
mkdir($this->vendorDir.'/b/b', 0777, true);
mkdir($this->vendorDir.'/c/c/foo', 0777, true);
@ -220,17 +236,17 @@ class AutoloadGeneratorTest extends TestCase
file_put_contents($this->vendorDir.'/b/b/test.php', '<?php class ClassMapBar {}');
file_put_contents($this->vendorDir.'/c/c/foo/test.php', '<?php class ClassMapBaz {}');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertTrue(file_exists($this->vendorDir.'/.composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->assertEquals(
array(
'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
'ClassMapBar' => $this->workingDir.'/composer-test-autoload/b/b/test.php',
'ClassMapBaz' => $this->workingDir.'/composer-test-autoload/c/c/foo/test.php',
),
include ($this->vendorDir.'/.composer/autoload_classmap.php')
include ($this->vendorDir.'/composer/autoload_classmap.php')
);
$this->assertAutoloadFiles('classmap5', $this->vendorDir.'/.composer', 'classmap');
$this->assertAutoloadFiles('classmap5', $this->vendorDir.'/composer', 'classmap');
}
public function testOverrideVendorsAutoloading()
@ -248,9 +264,9 @@ class AutoloadGeneratorTest extends TestCase
->method('getPackages')
->will($this->returnValue($packages));
mkdir($this->vendorDir.'/.composer', 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('override_vendors', $this->vendorDir.'/.composer');
mkdir($this->vendorDir.'/composer', 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/composer');
$this->assertAutoloadFiles('override_vendors', $this->vendorDir.'/composer');
}
public function testIncludePathFileGeneration()
@ -264,23 +280,29 @@ class AutoloadGeneratorTest extends TestCase
$b = new MemoryPackage("b/b", "1.0", "1.0");
$b->setIncludePaths(array("library"));
$c = new MemoryPackage("c", "1.0", "1.0");
$c->setIncludePaths(array("library"));
$packages[] = $a;
$packages[] = $b;
$packages[] = $c;
$this->repository->expects($this->once())
->method("getPackages")
->will($this->returnValue($packages));
mkdir($this->vendorDir."/.composer", 0777, true);
mkdir($this->vendorDir."/composer", 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/.composer");
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/composer");
$this->assertFileEquals(__DIR__.'/Fixtures/include_paths.php', $this->vendorDir.'/composer/include_paths.php');
$this->assertEquals(
array(
$this->vendorDir."/a/a/lib/",
$this->vendorDir."/b/b/library"
$this->vendorDir."/a/a/lib",
$this->vendorDir."/b/b/library",
$this->vendorDir."/c/library",
),
require($this->vendorDir."/.composer/include_paths.php")
require($this->vendorDir."/composer/include_paths.php")
);
}
@ -298,16 +320,16 @@ class AutoloadGeneratorTest extends TestCase
->method("getPackages")
->will($this->returnValue($packages));
mkdir($this->vendorDir."/.composer", 0777, true);
mkdir($this->vendorDir."/composer", 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/.composer");
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/composer");
$oldIncludePath = get_include_path();
require($this->vendorDir."/.composer/autoload.php");
require($this->vendorDir."/autoload.php");
$this->assertEquals(
$oldIncludePath.PATH_SEPARATOR.$this->vendorDir."/a/a/lib/",
$oldIncludePath.PATH_SEPARATOR.$this->vendorDir."/a/a/lib",
get_include_path()
);
@ -326,20 +348,20 @@ class AutoloadGeneratorTest extends TestCase
->method("getPackages")
->will($this->returnValue($packages));
mkdir($this->vendorDir."/.composer", 0777, true);
mkdir($this->vendorDir."/composer", 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/.composer");
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir."/composer");
$this->assertFalse(file_exists($this->vendorDir."/.composer/include_paths.php"));
$this->assertFalse(file_exists($this->vendorDir."/composer/include_paths.php"));
}
private function createClassFile($basedir)
{
if (!is_dir($basedir.'/.composersrc')) {
mkdir($basedir.'/.composersrc', 0777, true);
if (!is_dir($basedir.'/composersrc')) {
mkdir($basedir.'/composersrc', 0777, true);
}
file_put_contents($basedir.'/.composersrc/foo.php', '<?php class ClassMapFoo {}');
file_put_contents($basedir.'/composersrc/foo.php', '<?php class ClassMapFoo {}');
}
private function assertAutoloadFiles($name, $dir, $type = 'namespaces')

View File

@ -6,5 +6,5 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'ClassMapFoo' => $baseDir . '/.composersrc/foo.php',
'ClassMapFoo' => $baseDir . '/composersrc/foo.php',
);

View File

@ -6,5 +6,5 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
return array(
'ClassMapFoo' => $baseDir . '/.composersrc/foo.php',
'ClassMapFoo' => $baseDir . '/composersrc/foo.php',
);

View File

@ -6,5 +6,5 @@ $vendorDir = dirname(__DIR__);
$baseDir = $vendorDir;
return array(
'ClassMapFoo' => $baseDir . '/.composersrc/foo.php',
'ClassMapFoo' => $baseDir . '/composersrc/foo.php',
);

View File

@ -0,0 +1,41 @@
<?php
// autoload.php generated by Composer
if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
require __DIR__ . '/composer' . '/ClassLoader.php';
}
return call_user_func(function() {
$loader = new \Composer\Autoload\ClassLoader();
$composerDir = __DIR__ . '/composer';
$map = require $composerDir . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->add($namespace, $path);
}
$classMap = require $composerDir . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
spl_autoload_register(function($class) {
$dir = dirname(__DIR__) . '/';
$prefixes = array('Main\\Foo', 'Main\\Bar');
foreach ($prefixes as $prefix) {
if (0 !== strpos($class, $prefix)) {
continue;
}
$path = $dir . implode('/', array_slice(explode('\\', $class), 2)).'.php';
if (!stream_resolve_include_path($path)) {
return false;
}
require_once $path;
return true;
}
});
$loader->register();
return $loader;
});

View File

@ -0,0 +1,12 @@
<?php
// include_paths.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/a/a/lib',
$vendorDir . '/b/b/library',
$vendorDir . '/c/library',
);

View File

@ -18,6 +18,7 @@ use Composer\DependencyResolver\DefaultPolicy;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Literal;
use Composer\Package\Link;
use Composer\Package\AliasPackage;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Test\TestCase;
@ -99,6 +100,35 @@ class DefaultPolicyTest extends TestCase
$this->assertEquals($expected, $selected);
}
public function testSelectLocalReposFirst()
{
$this->repoImportant = new ArrayRepository;
$this->repo->addPackage($packageA = $this->getPackage('A', 'dev-master'));
$this->repo->addPackage($packageAAlias = new AliasPackage($packageA, '2.1.9999999.9999999-dev', '2.1.x-dev'));
$this->repoImportant->addPackage($packageAImportant = $this->getPackage('A', 'dev-feature-a'));
$this->repoImportant->addPackage($packageAAliasImportant = new AliasPackage($packageAImportant, '2.1.9999999.9999999-dev', '2.1.x-dev'));
$this->repoImportant->addPackage($packageA2Important = $this->getPackage('A', 'dev-master'));
$this->repoImportant->addPackage($packageA2AliasImportant = new AliasPackage($packageA2Important, '2.1.9999999.9999999-dev', '2.1.x-dev'));
$packageAAliasImportant->setRootPackageAlias(true);
$this->pool->addRepository($this->repoInstalled);
$this->pool->addRepository($this->repoImportant);
$this->pool->addRepository($this->repo);
$packages = $this->pool->whatProvides('a', new VersionConstraint('=', '2.1.9999999.9999999-dev'));
$literals = array();
foreach ($packages as $package) {
$literals[] = new Literal($package, true);
}
$expected = array(new Literal($packageAAliasImportant, true));
$selected = $this->policy->selectPreferedPackages($this->pool, array(), $literals);
$this->assertEquals($expected, $selected);
}
public function testSelectAllProviders()
{
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));

View File

@ -16,10 +16,17 @@ use Composer\Downloader\DownloadManager;
class DownloadManagerTest extends \PHPUnit_Framework_TestCase
{
protected $filesystem;
public function setUp()
{
$this->filesystem = $this->getMock('Composer\Util\Filesystem');
}
public function testSetGetDownloader()
{
$downloader = $this->createDownloaderMock();
$manager = new DownloadManager();
$manager = new DownloadManager(false, $this->filesystem);
$manager->setDownloader('test', $downloader);
$this->assertSame($downloader, $manager->getDownloader('test'));
@ -36,7 +43,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getInstallationSource')
->will($this->returnValue(null));
$manager = new DownloadManager();
$manager = new DownloadManager(false, $this->filesystem);
$this->setExpectedException('InvalidArgumentException');
@ -62,6 +69,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('dist'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloader'))
->getMock();
@ -93,6 +101,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('source'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloader'))
->getMock();
@ -126,6 +135,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('source'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloader'))
->getMock();
@ -157,6 +167,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('dist'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloader'))
->getMock();
@ -195,6 +206,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -218,7 +230,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getDistType')
->will($this->returnValue(null));
$manager = new DownloadManager();
$manager = new DownloadManager(false, $this->filesystem);
$this->setExpectedException('InvalidArgumentException');
$manager->download($package, 'target_dir');
@ -248,6 +260,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -283,6 +296,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -318,6 +332,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -354,6 +369,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -390,6 +406,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -414,7 +431,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getDistType')
->will($this->returnValue(null));
$manager = new DownloadManager();
$manager = new DownloadManager(false, $this->filesystem);
$manager->setPreferSource(true);
$this->setExpectedException('InvalidArgumentException');
@ -450,6 +467,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, $target, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
@ -486,6 +504,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock();
$manager
@ -526,6 +545,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, $target, 'vendor/pkg');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock();
$manager
@ -562,6 +582,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, 'vendor/pkg');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock();
$manager
@ -588,6 +609,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager

View File

@ -50,7 +50,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('https://example.com/composer/composer'));
$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'");
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref' && git remote add composer 'https://example.com/composer/composer'");
$processExecutor->expects($this->once())
->method('execute')
->with($this->equalTo($expectedGitCommand))
@ -71,19 +71,19 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('https://github.com/composer/composer'));
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
$expectedGitCommand = $this->getCmd("git clone 'git://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitCommand = $this->getCmd("git clone 'git://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref' && git remote add composer 'git://github.com/composer/composer'");
$processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedGitCommand))
->will($this->returnValue(1));
$expectedGitCommand = $this->getCmd("git clone 'https://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitCommand = $this->getCmd("git clone 'https://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref' && git remote add composer 'https://github.com/composer/composer'");
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($expectedGitCommand))
->will($this->returnValue(1));
$expectedGitCommand = $this->getCmd("git clone 'http://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitCommand = $this->getCmd("git clone 'http://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref' && git remote add composer 'http://github.com/composer/composer'");
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($expectedGitCommand))
@ -104,7 +104,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
*/
public function testDownloadThrowsRuntimeExceptionIfGitCommandFails()
{
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref' && git remote add composer 'https://example.com/composer/composer'");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
->method('getSourceReference')
@ -139,8 +139,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
public function testUpdate()
{
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url origin 'git://github.com/composer/composer' && git fetch origin && git fetch --tags origin && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url composer 'git://github.com/composer/composer' && git fetch composer && git fetch --tags composer && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain --untracked-files=no");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
@ -155,6 +155,10 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->with($this->equalTo($expectedGitResetCommand))
->will($this->returnValue(0));
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($expectedGitUpdateCommand))
->will($this->returnValue(0));
@ -168,8 +172,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
*/
public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
{
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url origin 'git://github.com/composer/composer' && git fetch origin && git fetch --tags origin && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url composer 'git://github.com/composer/composer' && git fetch composer && git fetch --tags composer && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain --untracked-files=no");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
@ -184,6 +188,10 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->with($this->equalTo($expectedGitResetCommand))
->will($this->returnValue(0));
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($expectedGitUpdateCommand))
->will($this->returnValue(1));
@ -194,7 +202,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
public function testRemove()
{
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain --untracked-files=no");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');

View File

@ -4,16 +4,16 @@ namespace Installer;
use Composer\Installer\InstallerInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
class Custom implements InstallerInterface
{
public $version = 'installer-v1';
public function supports($packageType) {}
public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function install(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function getInstallPath(PackageInterface $package) {}
}

View File

@ -4,16 +4,16 @@ namespace Installer;
use Composer\Installer\InstallerInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
class Custom2 implements InstallerInterface
{
public $version = 'installer-v2';
public function supports($packageType) {}
public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function install(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function getInstallPath(PackageInterface $package) {}
}

View File

@ -4,16 +4,16 @@ namespace Installer;
use Composer\Installer\InstallerInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
class Custom2 implements InstallerInterface
{
public $version = 'installer-v3';
public function supports($packageType) {}
public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function install(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {}
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
public function getInstallPath(PackageInterface $package) {}
}

View File

@ -21,7 +21,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
$this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
}
public function testVendorDirOutsideTheWorkingDir()

View File

@ -34,7 +34,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
->disableOriginalConstructor()
->getMock();
$this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
$this->io = $this->getMock('Composer\IO\IOInterface');
}

View File

@ -40,7 +40,7 @@ class LibraryInstallerTest extends TestCase
->disableOriginalConstructor()
->getMock();
$this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
$this->io = $this->getMock('Composer\IO\IOInterface');
}

View File

@ -22,7 +22,7 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
$this->io = $this->getMock('Composer\IO\IOInterface');

View File

@ -0,0 +1,115 @@
<?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\Installer;
use Composer\Repository\ArrayRepository;
use Composer\Repository\RepositoryManager;
use Composer\Repository\RepositoryInterface;
use Composer\Package\PackageInterface;
use Composer\Package\Link;
use Composer\Test\Mock\WritableRepositoryMock;
use Composer\Test\Mock\InstallationManagerMock;
class InstallerTest extends TestCase
{
/**
* @dataProvider provideInstaller
*/
public function testInstaller(PackageInterface $rootPackage, $repositories, array $options)
{
$io = $this->getMock('Composer\IO\IOInterface');
$downloadManager = $this->getMock('Composer\Downloader\DownloadManager');
$config = $this->getMock('Composer\Config');
$repositoryManager = new RepositoryManager($io, $config);
$repositoryManager->setLocalRepository(new WritableRepositoryMock());
$repositoryManager->setLocalDevRepository(new WritableRepositoryMock());
if (!is_array($repositories)) {
$repositories = array($repositories);
}
foreach ($repositories as $repository) {
$repositoryManager->addRepository($repository);
}
$locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
$installationManager = new InstallationManagerMock();
$eventDispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')->disableOriginalConstructor()->getMock();
$autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator');
$installer = new Installer($io, clone $rootPackage, $downloadManager, $repositoryManager, $locker, $installationManager, $eventDispatcher, $autoloadGenerator);
$result = $installer->run();
$this->assertTrue($result);
$expectedInstalled = isset($options['install']) ? $options['install'] : array();
$expectedUpdated = isset($options['update']) ? $options['update'] : array();
$expectedUninstalled = isset($options['uninstall']) ? $options['uninstall'] : array();
$installed = $installationManager->getInstalledPackages();
$this->assertSame($expectedInstalled, $installed);
$updated = $installationManager->getUpdatedPackages();
$this->assertSame($expectedUpdated, $updated);
$uninstalled = $installationManager->getUninstalledPackages();
$this->assertSame($expectedUninstalled, $uninstalled);
}
public function provideInstaller()
{
$cases = array();
// when A requires B and B requires A, and A is a non-published root package
// the install of B should succeed
$a = $this->getPackage('A', '1.0.0');
$a->setRequires(array(
new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
));
$b = $this->getPackage('B', '1.0.0');
$b->setRequires(array(
new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
));
$cases[] = array(
$a,
new ArrayRepository(array($b)),
array(
'install' => array($b)
),
);
// #480: when A requires B and B requires A, and A is a published root package
// only B should be installed, as A is the root
$a = $this->getPackage('A', '1.0.0');
$a->setRequires(array(
new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
));
$b = $this->getPackage('B', '1.0.0');
$b->setRequires(array(
new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
));
$cases[] = array(
$a,
new ArrayRepository(array($a, $b)),
array(
'install' => array($b)
),
);
return $cases;
}
}

View File

@ -128,6 +128,20 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
$this->assertJsonFormat($json, $data);
}
public function testFormatEmptyArray()
{
$data = array('test' => array(), 'test2' => new \stdClass);
$json = '{
"test": [
],
"test2": {
}
}';
$this->assertJsonFormat($json, $data);
}
public function testEscape()
{
$data = array("Metadata\\\"" => 'src/');

View File

@ -0,0 +1,56 @@
<?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\Mock;
use Composer\Installer\InstallationManager;
use Composer\Repository\RepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
class InstallationManagerMock extends InstallationManager
{
private $installed = array();
private $updated = array();
private $uninstalled = array();
public function install(RepositoryInterface $repo, InstallOperation $operation)
{
$this->installed[] = $operation->getPackage();
}
public function update(RepositoryInterface $repo, UpdateOperation $operation)
{
$this->updated[] = array($operation->getInitialPackage(), $operation->getTargetPackage());
}
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
{
$this->uninstalled[] = $operation->getPackage();
}
public function getInstalledPackages()
{
return $this->installed;
}
public function getUpdatedPackages()
{
return $this->updated;
}
public function getUninstalledPackages()
{
return $this->uninstalled;
}
}

View File

@ -0,0 +1,26 @@
<?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\Mock;
use Composer\Repository\ArrayRepository;
use Composer\Repository\WritableRepositoryInterface;
class WritableRepositoryMock extends ArrayRepository implements WritableRepositoryInterface
{
public function reload()
{
}
public function write()
{
}
}

View File

@ -89,7 +89,7 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
'homepage' => 'http://example.com',
'license' => array('MIT', 'GPLv3'),
'authors' => array(
array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org'),
array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org', 'role' => 'Developer'),
),
'require' => array(
'foo/bar' => '1.0',

View File

@ -15,6 +15,7 @@ namespace Composer\Test\Repository\Vcs;
use Composer\Downloader\TransportException;
use Composer\Repository\Vcs\GitHubDriver;
use Composer\Util\Filesystem;
use Composer\Config;
/**
* @author Beau Simensen <beau@dflydev.com>
@ -64,7 +65,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
->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 = new GitHubDriver($repoUrl, $io, new Config(), null, $remoteFilesystem);
$gitHubDriver->initialize();
$this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
@ -114,7 +115,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
->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 = new GitHubDriver($repoUrl, $io, new Config(), null, $remoteFilesystem);
$gitHubDriver->initialize();
$this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
@ -171,7 +172,14 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
// clean local clone if present
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9.]}i', '-', $repoSshUrl) . '/');
$fs->removeDirectory(sys_get_temp_dir() . '/composer-test');
$config = new Config();
$config->merge(array(
'config' => array(
'home' => sys_get_temp_dir() . '/composer-test',
),
));
$process->expects($this->at(0))
->method('execute')
@ -202,7 +210,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
->method('splitLines')
->will($this->returnValue(array('* test_master')));
$gitHubDriver = new GitHubDriver($repoUrl, $io, $process, $remoteFilesystem);
$gitHubDriver = new GitHubDriver($repoUrl, $io, $config, $process, $remoteFilesystem);
$gitHubDriver->initialize();
$this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());

View File

@ -14,6 +14,7 @@ namespace Composer\Test\Repository\Vcs;
use Composer\Repository\Vcs\SvnDriver;
use Composer\IO\NullIO;
use Composer\Config;
class SvnDriverTest extends \PHPUnit_Framework_TestCase
{
@ -39,8 +40,8 @@ class SvnDriverTest extends \PHPUnit_Framework_TestCase
->method('getErrorOutput')
->will($this->returnValue($output));
$svn = new SvnDriver('http://till:secret@corp.svn.local/repo', $console, $process);
$svn->getTags();
$svn = new SvnDriver('http://till:secret@corp.svn.local/repo', $console, new Config(), $process);
$svn->initialize();
}
private function getCmd($cmd)

View File

@ -19,6 +19,7 @@ use Composer\Repository\Vcs\GitDriver;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Composer\IO\NullIO;
use Composer\Config;
class VcsRepositoryTest extends \PHPUnit_Framework_TestCase
{
@ -123,7 +124,7 @@ class VcsRepositoryTest extends \PHPUnit_Framework_TestCase
'dev-master' => true,
);
$repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO);
$repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO, new Config());
$packages = $repo->getPackages();
$dumper = new ArrayDumper();

View File

@ -19,26 +19,29 @@ use Composer\Util\Filesystem;
abstract class TestCase extends \PHPUnit_Framework_TestCase
{
private static $versionParser;
private static $parser;
public static function setUpBeforeClass()
protected static function getVersionParser()
{
if (!self::$versionParser) {
self::$versionParser = new VersionParser();
if (!self::$parser) {
self::$parser = new VersionParser();
}
return self::$parser;
}
protected function getVersionConstraint($operator, $version)
{
return new VersionConstraint(
$operator,
self::$versionParser->normalize($version)
self::getVersionParser()->normalize($version)
);
}
protected function getPackage($name, $version)
{
$normVersion = self::$versionParser->normalize($version);
$normVersion = self::getVersionParser()->normalize($version);
return new MemoryPackage($name, $normVersion, $version);
}

View File

@ -57,30 +57,48 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
public function testHttpProxy()
{
$_SERVER['http_proxy'] = 'http://username:password@proxyserver.net:1234';
$_SERVER['HTTP_PROXY'] = 'http://proxyserver';
$_SERVER['http_proxy'] = 'http://username:password@proxyserver.net:3128/';
$_SERVER['HTTP_PROXY'] = 'http://proxyserver/';
$context = StreamContextFactory::getContext(array('http' => array('method' => 'GET')));
$options = stream_context_get_options($context);
$this->assertEquals(array('http' => array(
'proxy' => 'tcp://proxyserver.net:1234',
'proxy' => 'tcp://proxyserver.net:3128',
'request_fulluri' => true,
'method' => 'GET',
'header' => "Proxy-Authorization: Basic " . base64_encode('username:password') . "\r\n"
)), $options);
}
public function testSSLProxy()
public function testHttpProxyWithoutPort()
{
$_SERVER['http_proxy'] = 'https://proxyserver';
$_SERVER['http_proxy'] = 'http://username:password@proxyserver.net';
$context = StreamContextFactory::getContext(array('http' => array('method' => 'GET')));
$options = stream_context_get_options($context);
$this->assertEquals(array('http' => array(
'proxy' => 'tcp://proxyserver.net:80',
'request_fulluri' => true,
'method' => 'GET',
'header' => "Proxy-Authorization: Basic " . base64_encode('username:password') . "\r\n"
)), $options);
}
/**
* @dataProvider dataSSLProxy
*/
public function testSSLProxy($expected, $proxy)
{
$_SERVER['http_proxy'] = $proxy;
if (extension_loaded('openssl')) {
$context = StreamContextFactory::getContext();
$options = stream_context_get_options($context);
$this->assertSame(array('http' => array(
'proxy' => 'ssl://proxyserver',
$this->assertEquals(array('http' => array(
'proxy' => $expected,
'request_fulluri' => true,
)), $options);
} else {
@ -92,4 +110,12 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
}
}
}
public function dataSSLProxy()
{
return array(
array('ssl://proxyserver:443', 'https://proxyserver/'),
array('ssl://proxyserver:8443', 'https://proxyserver:8443'),
);
}
}