From 2dbc9447b5a9cc7ece8a413edacc3665f0a7005c Mon Sep 17 00:00:00 2001 From: Tobias Tom Date: Thu, 21 Aug 2014 11:17:08 +0200 Subject: [PATCH 01/83] Added some details about authentication handling. This details are more or less copied directly from [Authentication management in Composer](http://seld.be/notes/authentication-management-in-composer). --- .../handling-private-packages-with-satis.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/articles/handling-private-packages-with-satis.md b/doc/articles/handling-private-packages-with-satis.md index 473c4f9ed..45cfd9eb8 100644 --- a/doc/articles/handling-private-packages-with-satis.md +++ b/doc/articles/handling-private-packages-with-satis.md @@ -143,6 +143,24 @@ Example using HTTP over SSL using a client certificate: > **Tip:** See [ssl context options](http://www.php.net/manual/en/context.ssl.php) for more information. +### Authentification + +When your private repositories are password protected, you can store the authentification details permanently. +The first time Composer needs to authenticate against some domain it will prompt you for a username/password +and then you will be asked whether you want to store it. + +The storage can be done either globally in the `COMPOSER_HOME/auth.json` file (`COMPOSER_HOME` defaults to +`~/.composer` or `%APPDATA%/Composer` on Windows) or also in the project directory directly sitting besides your +composer.json. + +You can also configure these by hand using the config command if you need to configure a production machine +to be able to run non-interactive installs. For example to enter credentials for example.org one could type: + + composer config http-basic.example.org username password + +That will store it in the current directory's auth.json, but if you want it available globally you can use the +`--global` (`-g`) flag. + ### Downloads When GitHub or BitBucket repositories are mirrored on your local satis, the build process will include From dc9429c82ae5bfb089778e48328b187aa279188a Mon Sep 17 00:00:00 2001 From: SofHad Date: Fri, 26 Dec 2014 01:43:36 +0100 Subject: [PATCH 02/83] Remove deprecated TableHelper and update table style --- src/Composer/Command/LicensesCommand.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 8ab9d94b4..5015dd7d1 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -18,7 +18,8 @@ use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Composer\Package\PackageInterface; use Composer\Repository\RepositoryInterface; -use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableStyle; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -73,9 +74,15 @@ EOT $output->writeln('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').''); $output->writeln('Dependencies:'); - $table = $this->getHelperSet()->get('table'); - $table->setLayout(TableHelper::LAYOUT_BORDERLESS); - $table->setHorizontalBorderChar(''); + $table = new Table($output); + $style = new TableStyle(); + $style + ->setHorizontalBorderChar('-') + ->setVerticalBorderChar('|') + ->setCrossingChar(' ') + ; + $table->setStyle($style); + $table->setHeaders(array('Name', 'Version', 'License')); foreach ($packages as $package) { $table->addRow(array( $package->getPrettyName(), From 844b57bf7fd76933d9d9afdf270c4654f4f5cb00 Mon Sep 17 00:00:00 2001 From: SofHad Date: Sat, 27 Dec 2014 16:16:36 +0100 Subject: [PATCH 03/83] Fixed render method --- src/Composer/Command/LicensesCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 5015dd7d1..073804427 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -90,7 +90,7 @@ EOT implode(', ', $package->getLicense()) ?: 'none', )); } - $table->render($output); + $table->render(); break; case 'json': From 3bf1ee939b750b976e53097a2fca919529914094 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sat, 18 Oct 2014 12:46:13 +0200 Subject: [PATCH 04/83] Fixed validator to accept 'a/b' and 'a/b ~2.3' --- src/Composer/Command/InitCommand.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 462b6d438..d4cd56b57 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -328,6 +328,7 @@ EOT return $result; } + $versionParser = new VersionParser(); while (null !== $package = $dialog->ask($output, $prompt)) { $matches = $this->findPackages($package); @@ -353,22 +354,32 @@ EOT $output->writeln($choices); $output->writeln(''); - $validator = function ($selection) use ($matches) { + $validator = function ($selection) use ($matches, $versionParser) { if ('' === $selection) { return false; } - if (!is_numeric($selection) && preg_match('{^\s*(\S+)\s+(\S.*)\s*$}', $selection, $matches)) { - return $matches[1].' '.$matches[2]; + if (is_numeric($selection) && isset($matches[(int) $selection])) { + $package = $matches[(int) $selection]; + + return $package['name']; } - if (!isset($matches[(int) $selection])) { - throw new \Exception('Not a valid selection'); + if (preg_match('{^\s*(?P[\S/]+)(?:\s+(?P\S+))?\s*$}', $selection, $packageMatches)) { + if (isset($packageMatches['version'])) { + // parsing `acme/example ~2.3` + + // validate version constraint + $versionParser->parseConstraints($packageMatches['version']); + + return $packageMatches['name'].' '.$packageMatches['version']; + } + + // parsing `acme/example` + return $packageMatches['name']; } - $package = $matches[(int) $selection]; - - return $package['name']; + throw new \Exception('Not a valid selection'); }; $package = $dialog->askAndValidate($output, $dialog->getQuestion('Enter package # to add, or the complete package name if it is not listed', false, ':'), $validator, 3); From abc9d60fcc7a53b9baa633fc7f61de5d3355df9e Mon Sep 17 00:00:00 2001 From: rkerner Date: Mon, 2 Feb 2015 14:36:50 +0100 Subject: [PATCH 05/83] added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches --- res/composer-schema.json | 7 ++ .../Package/Loader/RootPackageLoader.php | 11 +++ .../Package/Loader/RootPackageLoaderTest.php | 76 +++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/res/composer-schema.json b/res/composer-schema.json index 905199247..3f3f595cd 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -367,6 +367,13 @@ "format": "uri" } } + }, + "non-feature-branches": { + "type": ["array"], + "description": "A set of string or regex patterns for non-numeric branch names that will not be handles as feature branches.", + "items": { + "type": "string" + } } } } diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index a067fa6a8..face114af 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -272,7 +272,18 @@ class RootPackageLoader extends ArrayLoader ) { $branch = preg_replace('{^dev-}', '', $version); $length = PHP_INT_MAX; + + $nonFeatureBranches = ''; + if(!empty($config['non-feature-branches'])) { + $nonFeatureBranches = implode('|', $config['non-feature-branches']); + } + foreach ($branches as $candidate) { + // return directly, if branch is configured to be non-feature branch + if($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) { + return $version; + } + // do not compare against other feature branches if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) { continue; diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php index 1a6a3bf78..d3bab647f 100644 --- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php @@ -153,4 +153,80 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase 'qux/quux' => BasePackage::STABILITY_RC, ), $package->getStabilityFlags()); } + + public function testFeatureBranchPrettyVersion() + { + if (!function_exists('proc_open')) { + $this->markTestSkipped('proc_open() is not available'); + } + + $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') + ->disableOriginalConstructor() + ->getMock(); + + $self = $this; + + /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */ + $processExecutor = new ProcessExecutorMock(function($command, &$output = null, $cwd = null) use ($self) { + if (0 === strpos($command, 'git rev-list')) { + $output = ""; + return 0; + } + + if ('git branch --no-color --no-abbrev -v' !== $command) { + return 1; //0; + } + + $self->assertEquals('git branch --no-color --no-abbrev -v', $command); + + $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n"; + + return 0; + }); + + $config = new Config; + $config->merge(array('repositories' => array('packagist' => false))); + $loader = new RootPackageLoader($manager, $config, null, $processExecutor); + $package = $loader->load(array('require' => array('foo/bar' => 'self.version'))); + + $this->assertEquals("dev-master", $package->getPrettyVersion()); + } + + public function testNonFeatureBranchPrettyVersion() + { + if (!function_exists('proc_open')) { + $this->markTestSkipped('proc_open() is not available'); + } + + $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') + ->disableOriginalConstructor() + ->getMock(); + + $self = $this; + + /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */ + $processExecutor = new ProcessExecutorMock(function($command, &$output = null, $cwd = null) use ($self) { + if (0 === strpos($command, 'git rev-list')) { + $output = ""; + return 0; + } + + if ('git branch --no-color --no-abbrev -v' !== $command) { + return 1; //0; + } + + $self->assertEquals('git branch --no-color --no-abbrev -v', $command); + + $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n"; + + return 0; + }); + + $config = new Config; + $config->merge(array('repositories' => array('packagist' => false))); + $loader = new RootPackageLoader($manager, $config, null, $processExecutor); + $package = $loader->load(array('require' => array('foo/bar' => 'self.version'), "non-feature-branches" => array("latest-.*"))); + + $this->assertEquals("dev-latest-production", $package->getPrettyVersion()); + } } From 1b1074047329da1f30832651eba4ca432a3f1147 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 3 Feb 2015 13:44:42 +0100 Subject: [PATCH 06/83] Added --list to run-script command, closes #3671 --- src/Composer/Command/RunScriptCommand.php | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index f01a5febe..91a9b2abe 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -54,10 +54,11 @@ class RunScriptCommand extends Command ->setName('run-script') ->setDescription('Run the scripts defined in composer.json.') ->setDefinition(array( - new InputArgument('script', InputArgument::REQUIRED, 'Script name to run.'), + new InputArgument('script', InputArgument::OPTIONAL, 'Script name to run.'), new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''), new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'), + new InputOption('list', 'l', InputOption::VALUE_NONE, 'List scripts.'), )) ->setHelp(<<run-script command runs scripts defined in composer.json: @@ -70,6 +71,12 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { + if ($input->getOption('list')) { + return $this->listScripts($input, $output); + } elseif (!$input->getArgument('script')) { + throw new \RunTimeException('Missing required argument "script"'); + } + $script = $input->getArgument('script'); if (!in_array($script, $this->commandEvents) && !in_array($script, $this->scriptEvents)) { if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) { @@ -97,4 +104,20 @@ EOT return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args); } + + protected function listScripts(InputInterface $input, OutputInterface $output) + { + $scripts = $this->getComposer()->getPackage()->getScripts(); + + if (!count($scripts)) { + return 0; + } + + $output->writeln('scripts:'); + foreach ($scripts as $name => $script) { + $output->writeln(' ' . $name); + } + + return 0; + } } From 1575f19ef274f96f479a2dba0b6c4cbe8f088f34 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 3 Feb 2015 15:26:02 +0100 Subject: [PATCH 07/83] Updated documentation --- doc/03-cli.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 40478ee9b..dd1121c80 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -507,8 +507,13 @@ Lists the name, version and license of every package installed. Use ## run-script +### Options + +* **--no-dev:** Disable dev mode +* **--list:** List user defined scripts + To run [scripts](articles/scripts.md) manually you can use this command, -just give it the script name and optionally --no-dev to disable the dev mode. +just give it the script name and optionally any required arguments. ## diagnose From a8b8a2e143a44dd9b0f6e40d1dfd3367f0ea1623 Mon Sep 17 00:00:00 2001 From: rkerner Date: Wed, 11 Feb 2015 15:57:33 +0100 Subject: [PATCH 08/83] * added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches * added documentation to doc/04-schema.md --- doc/04-schema.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/04-schema.md b/doc/04-schema.md index 96641e8fe..a7be21766 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -786,3 +786,32 @@ The example will include `/dir/foo/bar/file`, `/foo/bar/baz`, `/file.php`, Optional. ← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) → + +### non-feature-branches + +A list of regex patterns of branch names that are non-numeric (e.g. "latest" or something), that will NOT be handled as feature branches. This is an array of string. + +If you have non-numeric branch names, for example like "latest", "current", "latest-stable" +or something, that do not look like a version number, then composer handles such branches +as feature branches. This means it searches for parent branches, that look like a version +or ends at special branches (like master) and the root package version number becomes the +version of the parent branch or at least master or something. + +To handle non-numeric named branches as versions instead of searching for a parent branch +with a valid version or special branch name like master, you can set patterns for branch +names, that should be handled as dev version branches. + +An example: + If you have a testing branch, that is heavily maintained during a testing phase and is + deployed to your staging environment, normally "composer show -s" will give you "versions : * dev-master". + + If you configure latest-.* as a pattern for non-feature-branches like this: + + { + "non-feature-branches": ["latest-.*"] + } + + Then "composer show -s" will give you "versions : * dev-latest-testing". + + +Optional. \ No newline at end of file From 62636cdd64b9e1653e617605fec90c9f8f1d0a2c Mon Sep 17 00:00:00 2001 From: rkerner Date: Wed, 11 Feb 2015 15:59:26 +0100 Subject: [PATCH 09/83] * added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches * added documentation to doc/04-schema.md * fixed indentation --- doc/04-schema.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index a7be21766..6c0a42116 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -802,16 +802,16 @@ with a valid version or special branch name like master, you can set patterns fo names, that should be handled as dev version branches. An example: - If you have a testing branch, that is heavily maintained during a testing phase and is - deployed to your staging environment, normally "composer show -s" will give you "versions : * dev-master". +If you have a testing branch, that is heavily maintained during a testing phase and is +deployed to your staging environment, normally "composer show -s" will give you "versions : * dev-master". - If you configure latest-.* as a pattern for non-feature-branches like this: +If you configure latest-.* as a pattern for non-feature-branches like this: { "non-feature-branches": ["latest-.*"] } - Then "composer show -s" will give you "versions : * dev-latest-testing". +Then "composer show -s" will give you "versions : * dev-latest-testing". Optional. \ No newline at end of file From 86c7dfcd94aedbc9037465d2ce526f3b5e558583 Mon Sep 17 00:00:00 2001 From: rkerner Date: Wed, 11 Feb 2015 16:00:43 +0100 Subject: [PATCH 10/83] * added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches * added documentation to doc/04-schema.md * fixed indentation --- doc/04-schema.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index 6c0a42116..0fd8fd6ed 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -785,8 +785,6 @@ The example will include `/dir/foo/bar/file`, `/foo/bar/baz`, `/file.php`, Optional. -← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) → - ### non-feature-branches A list of regex patterns of branch names that are non-numeric (e.g. "latest" or something), that will NOT be handled as feature branches. This is an array of string. @@ -814,4 +812,6 @@ If you configure latest-.* as a pattern for non-feature-branches like this: Then "composer show -s" will give you "versions : * dev-latest-testing". -Optional. \ No newline at end of file +Optional. + +← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) → \ No newline at end of file From 40b498c96e5208df324d31088ac35dba78c258dc Mon Sep 17 00:00:00 2001 From: rkerner Date: Wed, 11 Feb 2015 16:01:41 +0100 Subject: [PATCH 11/83] * added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches * added documentation to doc/04-schema.md * fixed indentation and styling --- doc/04-schema.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index 0fd8fd6ed..b0b904687 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -801,7 +801,7 @@ names, that should be handled as dev version branches. An example: If you have a testing branch, that is heavily maintained during a testing phase and is -deployed to your staging environment, normally "composer show -s" will give you "versions : * dev-master". +deployed to your staging environment, normally "composer show -s" will give you `versions : * dev-master`. If you configure latest-.* as a pattern for non-feature-branches like this: @@ -809,8 +809,7 @@ If you configure latest-.* as a pattern for non-feature-branches like this: "non-feature-branches": ["latest-.*"] } -Then "composer show -s" will give you "versions : * dev-latest-testing". - +Then "composer show -s" will give you `versions : * dev-latest-testing`. Optional. From 38d546da453762c37ee19e6ee9f4f59ce4af5b74 Mon Sep 17 00:00:00 2001 From: rkerner Date: Wed, 11 Feb 2015 16:03:17 +0100 Subject: [PATCH 12/83] * added non-feature-branches to handle non-numeric branches matching configured patterns not been handled as feature branches * added documentation to doc/04-schema.md * fixed indentation and styling --- doc/04-schema.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/04-schema.md b/doc/04-schema.md index b0b904687..dc68f6963 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -799,7 +799,11 @@ To handle non-numeric named branches as versions instead of searching for a pare with a valid version or special branch name like master, you can set patterns for branch names, that should be handled as dev version branches. +This is really helpful when you have dependencies using "self.version", so that not dev-master, +but the same branch is installed (in the example: latest-testing). + An example: + If you have a testing branch, that is heavily maintained during a testing phase and is deployed to your staging environment, normally "composer show -s" will give you `versions : * dev-master`. From c9cff6387a874e15e191119349a4f33c488b679d Mon Sep 17 00:00:00 2001 From: Matthias Derer Date: Fri, 13 Feb 2015 00:37:18 +0100 Subject: [PATCH 13/83] removed requirements from the root package should we install from the lock file --- src/Composer/Installer.php | 3 ++ ...rements-do-not-affect-locked-versions.test | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/Composer/Test/Fixtures/installer/root-requirements-do-not-affect-locked-versions.test diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 3594336e3..e3e380f07 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -355,6 +355,9 @@ class Installer $installFromLock = false; if (!$this->update && $this->locker->isLocked()) { $installFromLock = true; + // we are removing all requirements from the root package so only the lock file is relevant for installation rules + $this->package->setRequires(array()); + $this->package->setDevRequires(array()); try { $lockedRepository = $this->locker->getLockedRepository($withDevReqs); } catch (\RuntimeException $e) { diff --git a/tests/Composer/Test/Fixtures/installer/root-requirements-do-not-affect-locked-versions.test b/tests/Composer/Test/Fixtures/installer/root-requirements-do-not-affect-locked-versions.test new file mode 100644 index 000000000..15d1b4ef5 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/root-requirements-do-not-affect-locked-versions.test @@ -0,0 +1,41 @@ +--TEST-- +The locked version will not get overwritten by an install +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "foo/bar", "version": "1.0.0" }, + { "name": "foo/baz", "version": "1.0.0" }, + { "name": "foo/baz", "version": "2.0.0" } + ] + } + ], + "require": { + "foo/bar": "2.0.0", + "foo/baz": "2.0.0" + } +} +--LOCK-- +{ + "packages": [ + { "name": "foo/bar", "version": "1.0.0" }, + { "name": "foo/baz", "version": "2.0.0" } + ], + "packages-dev": null, + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false +} +--INSTALLED-- +[ + { "name": "foo/bar", "version": "1.0.0" }, + { "name": "foo/baz", "version": "1.0.0" } +] +--RUN-- +install +--EXPECT-- +Updating foo/baz (1.0.0) to foo/baz (2.0.0) From 1425bb7fc326e17e657193c9f6eab8184811d806 Mon Sep 17 00:00:00 2001 From: Matthias Derer Date: Mon, 16 Feb 2015 13:46:59 +0100 Subject: [PATCH 14/83] added tests to reproduce the bug --- ...e-installed-when-installing-from-lock.test | 39 +++++++++++++++++++ ...aced-packages-should-not-be-installed.test | 24 ++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test create mode 100644 tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test new file mode 100644 index 000000000..6d0602159 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test @@ -0,0 +1,39 @@ +--TEST-- +Requiring a replaced package in a version, that is not provided by the replacing package, should result in a conflict, when installing from lock +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"} }, + { "name": "foo/replaced", "version": "1.0.0" }, + { "name": "foo/replaced", "version": "2.0.0" } + ] + } + ], + "require": { + "foo/original": "1.0.0", + "foo/replaced": "2.0.0" + } +} +--LOCK-- +{ + "packages": [ + { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"} }, + { "name": "foo/replaced", "version": "2.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} +--RUN-- +install +--EXPECT-EXIT-CODE-- +2 +--EXPECT-- diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test new file mode 100644 index 000000000..0d1ea7701 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test @@ -0,0 +1,24 @@ +--TEST-- +Requiring a replaced package in a version, that is not provided by the replacing package, should result in a conflict +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"} }, + { "name": "foo/replaced", "version": "1.0.0" }, + { "name": "foo/replaced", "version": "2.0.0" } + ] + } + ], + "require": { + "foo/original": "1.0.0", + "foo/replaced": "2.0.0" + } +} +--RUN-- +install +--EXPECT-EXIT-CODE-- +2 +--EXPECT-- From 813fd0b70392bc1a9f7aea8fad5b915ef3c1c715 Mon Sep 17 00:00:00 2001 From: Vladimir Kartaviy Date: Mon, 16 Feb 2015 15:23:06 +0200 Subject: [PATCH 15/83] Added missing $learnedWhy property --- src/Composer/DependencyResolver/Solver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 19e69913b..77a945f20 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -40,6 +40,7 @@ class Solver protected $branches = array(); protected $problems = array(); protected $learnedPool = array(); + protected $learnedWhy = array(); public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed) { From ef92a062059b91c5951874183168e96d9bcdb224 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Mon, 16 Feb 2015 15:58:58 +0100 Subject: [PATCH 16/83] composer config repositories.packagist false closes #3728, closes #3713, closes #3290, not sure about #3025 --- src/Composer/Command/ConfigCommand.php | 90 ++++++------ .../Fixtures/composer-repositories.json | 6 + .../config-with-exampletld-repository.json | 10 ++ .../config/config-with-packagist-false.json | 7 + .../Test/Config/JsonConfigSourceTest.php | 129 ++++++++++++------ 5 files changed, 157 insertions(+), 85 deletions(-) create mode 100644 tests/Composer/Test/Config/Fixtures/composer-repositories.json create mode 100644 tests/Composer/Test/Config/Fixtures/config/config-with-exampletld-repository.json create mode 100644 tests/Composer/Test/Config/Fixtures/config/config-with-packagist-false.json diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index e21c99c8a..1ebb5bcc0 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -237,48 +237,6 @@ EOT $values = $input->getArgument('setting-value'); // what the user is trying to add/change - // handle repositories - if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { - if ($input->getOption('unset')) { - return $this->configSource->removeRepository($matches[1]); - } - - if (2 !== count($values)) { - throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs http://bar.com'); - } - - return $this->configSource->addRepository($matches[1], array( - 'type' => $values[0], - 'url' => $values[1], - )); - } - - // handle github-oauth - if (preg_match('/^(github-oauth|http-basic)\.(.+)/', $settingKey, $matches)) { - if ($input->getOption('unset')) { - $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]); - $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); - - return; - } - - if ($matches[1] === 'github-oauth') { - if (1 !== count($values)) { - throw new \RuntimeException('Too many arguments, expected only one token'); - } - $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); - $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]); - } elseif ($matches[1] === 'http-basic') { - if (2 !== count($values)) { - throw new \RuntimeException('Expected two arguments (username, password), got '.count($values)); - } - $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); - $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1])); - } - - return; - } - $booleanValidator = function ($val) { return in_array($val, array('true', 'false', '1', '0'), true); }; $booleanNormalizer = function ($val) { return $val !== 'false' && (bool) $val; }; @@ -402,6 +360,54 @@ EOT } } + // handle repositories + if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { + if ($input->getOption('unset')) { + return $this->configSource->removeRepository($matches[1]); + } + + if (2 === count($values)) { + return $this->configSource->addRepository($matches[1], array( + 'type' => $values[0], + 'url' => $values[1], + )); + } + + if (1 === count($values) && $booleanValidator($values[0])) { + if (false === $booleanNormalizer($values[0])) { + return $this->configSource->addRepository($matches[1], false); + } + } + + throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs http://bar.com'); + } + + // handle github-oauth + if (preg_match('/^(github-oauth|http-basic)\.(.+)/', $settingKey, $matches)) { + if ($input->getOption('unset')) { + $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]); + $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); + + return; + } + + if ($matches[1] === 'github-oauth') { + if (1 !== count($values)) { + throw new \RuntimeException('Too many arguments, expected only one token'); + } + $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); + $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]); + } elseif ($matches[1] === 'http-basic') { + if (2 !== count($values)) { + throw new \RuntimeException('Expected two arguments (username, password), got '.count($values)); + } + $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); + $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1])); + } + + return; + } + throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command'); } diff --git a/tests/Composer/Test/Config/Fixtures/composer-repositories.json b/tests/Composer/Test/Config/Fixtures/composer-repositories.json new file mode 100644 index 000000000..fc303ec38 --- /dev/null +++ b/tests/Composer/Test/Config/Fixtures/composer-repositories.json @@ -0,0 +1,6 @@ +{ + "name": "my-vend/my-app", + "license": "MIT", + "repositories": { + } +} diff --git a/tests/Composer/Test/Config/Fixtures/config/config-with-exampletld-repository.json b/tests/Composer/Test/Config/Fixtures/config/config-with-exampletld-repository.json new file mode 100644 index 000000000..085c875c5 --- /dev/null +++ b/tests/Composer/Test/Config/Fixtures/config/config-with-exampletld-repository.json @@ -0,0 +1,10 @@ +{ + "name": "my-vend/my-app", + "license": "MIT", + "repositories": { + "example_tld": { + "type": "git", + "url": "example.tld" + } + } +} diff --git a/tests/Composer/Test/Config/Fixtures/config/config-with-packagist-false.json b/tests/Composer/Test/Config/Fixtures/config/config-with-packagist-false.json new file mode 100644 index 000000000..c4d884527 --- /dev/null +++ b/tests/Composer/Test/Config/Fixtures/config/config-with-packagist-false.json @@ -0,0 +1,7 @@ +{ + "name": "my-vend/my-app", + "license": "MIT", + "repositories": { + "packagist": false + } +} diff --git a/tests/Composer/Test/Config/JsonConfigSourceTest.php b/tests/Composer/Test/Config/JsonConfigSourceTest.php index b7a3b592c..529532263 100644 --- a/tests/Composer/Test/Config/JsonConfigSourceTest.php +++ b/tests/Composer/Test/Config/JsonConfigSourceTest.php @@ -18,6 +18,9 @@ use Composer\Util\Filesystem; class JsonConfigSourceTest extends \PHPUnit_Framework_TestCase { + /** @var Filesystem */ + private $fs; + /** @var string */ private $workingDir; protected function fixturePath($name) @@ -39,6 +42,89 @@ class JsonConfigSourceTest extends \PHPUnit_Framework_TestCase } } + public function testAddRepository() + { + $config = $this->workingDir.'/composer.json'; + copy($this->fixturePath('composer-repositories.json'), $config); + $jsonConfigSource = new JsonConfigSource(new JsonFile($config)); + $jsonConfigSource->addRepository('example_tld', array('type' => 'git', 'url' => 'example.tld')); + + $this->assertFileEquals($this->fixturePath('config/config-with-exampletld-repository.json'), $config); + } + + public function testRemoveRepository() + { + $config = $this->workingDir.'/composer.json'; + copy($this->fixturePath('config/config-with-exampletld-repository.json'), $config); + $jsonConfigSource = new JsonConfigSource(new JsonFile($config)); + $jsonConfigSource->removeRepository('example_tld'); + + $this->assertFileEquals($this->fixturePath('composer-repositories.json'), $config); + } + + public function testAddPackagistRepositoryWithFalseValue() + { + $config = $this->workingDir.'/composer.json'; + copy($this->fixturePath('composer-repositories.json'), $config); + $jsonConfigSource = new JsonConfigSource(new JsonFile($config)); + $jsonConfigSource->addRepository('packagist', false); + + $this->assertFileEquals($this->fixturePath('config/config-with-packagist-false.json'), $config); + } + + public function testRemovePackagist() + { + $config = $this->workingDir.'/composer.json'; + copy($this->fixturePath('config/config-with-packagist-false.json'), $config); + $jsonConfigSource = new JsonConfigSource(new JsonFile($config)); + $jsonConfigSource->removeRepository('packagist'); + + $this->assertFileEquals($this->fixturePath('composer-repositories.json'), $config); + } + + /** + * Test addLink() + * + * @param string $sourceFile Source file + * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) + * @param string $name Name + * @param string $value Value + * @param string $compareAgainst File to compare against after making changes + * + * @dataProvider provideAddLinkData + */ + public function testAddLink($sourceFile, $type, $name, $value, $compareAgainst) + { + $composerJson = $this->workingDir.'/composer.json'; + copy($sourceFile, $composerJson); + $jsonConfigSource = new JsonConfigSource(new JsonFile($composerJson)); + + $jsonConfigSource->addLink($type, $name, $value); + + $this->assertFileEquals($compareAgainst, $composerJson); + } + + /** + * Test removeLink() + * + * @param string $sourceFile Source file + * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) + * @param string $name Name + * @param string $compareAgainst File to compare against after making changes + * + * @dataProvider provideRemoveLinkData + */ + public function testRemoveLink($sourceFile, $type, $name, $compareAgainst) + { + $composerJson = $this->workingDir.'/composer.json'; + copy($sourceFile, $composerJson); + $jsonConfigSource = new JsonConfigSource(new JsonFile($composerJson)); + + $jsonConfigSource->removeLink($type, $name); + + $this->assertFileEquals($compareAgainst, $composerJson); + } + protected function addLinkDataArguments($type, $name, $value, $fixtureBasename, $before) { return array( @@ -88,28 +174,6 @@ class JsonConfigSourceTest extends \PHPUnit_Framework_TestCase ); } - /** - * Test addLink() - * - * @param string $sourceFile Source file - * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) - * @param string $name Name - * @param string $value Value - * @param string $compareAgainst File to compare against after making changes - * - * @dataProvider provideAddLinkData - */ - public function testAddLink($sourceFile, $type, $name, $value, $compareAgainst) - { - $composerJson = $this->workingDir.'/composer.json'; - copy($sourceFile, $composerJson); - $jsonConfigSource = new JsonConfigSource(new JsonFile($composerJson)); - - $jsonConfigSource->addLink($type, $name, $value); - - $this->assertFileEquals($compareAgainst, $composerJson); - } - protected function removeLinkDataArguments($type, $name, $fixtureBasename, $after = null) { return array( @@ -156,25 +220,4 @@ class JsonConfigSourceTest extends \PHPUnit_Framework_TestCase $this->removeLinkDataArguments('conflict', 'my-vend/my-old-app', 'conflict-to-twoOfEverything', $twoOfEverything), ); } - - /** - * Test removeLink() - * - * @param string $sourceFile Source file - * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) - * @param string $name Name - * @param string $compareAgainst File to compare against after making changes - * - * @dataProvider provideRemoveLinkData - */ - public function testRemoveLink($sourceFile, $type, $name, $compareAgainst) - { - $composerJson = $this->workingDir.'/composer.json'; - copy($sourceFile, $composerJson); - $jsonConfigSource = new JsonConfigSource(new JsonFile($composerJson)); - - $jsonConfigSource->removeLink($type, $name); - - $this->assertFileEquals($compareAgainst, $composerJson); - } } From 47d75f77d5cdbe63b2fe2bfbe9db4712ba98a812 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Mon, 16 Feb 2015 16:54:52 +0100 Subject: [PATCH 17/83] Let's be gentle and allow FALSE too --- src/Composer/Command/ConfigCommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 1ebb5bcc0..9773ea885 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -373,8 +373,9 @@ EOT )); } - if (1 === count($values) && $booleanValidator($values[0])) { - if (false === $booleanNormalizer($values[0])) { + if (1 === count($values)) { + $bool = strtolower($values[0]); + if (true === $booleanValidator($bool) && false === $booleanNormalizer($bool)) { return $this->configSource->addRepository($matches[1], false); } } From e5ede671d296edb9debe862360807d72386103a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Pr=C3=A9vot?= Date: Sun, 15 Feb 2015 23:20:45 -0400 Subject: [PATCH 18/83] Config Git repository user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One can’t assume a Git user is already setup for the tests. --- .../Package/Archiver/ArchivableFilesFinderTest.php | 2 ++ .../Test/Package/Archiver/ArchiveManagerTest.php | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php index bc74be1e9..e9233f3cb 100644 --- a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php @@ -187,6 +187,8 @@ class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase $this->finder = new ArchivableFilesFinder($this->sources, array()); $this->assertArchivableFiles($this->getArchivedFiles('git init && '. + 'git config user.email "you@example.com" && '. + 'git config user.name "Your Name" && '. 'git add .git* && '. 'git commit -m "ignore rules" && '. 'git add . && '. diff --git a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php index aa98a62a2..f4d343e63 100644 --- a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php @@ -78,6 +78,18 @@ class ArchiveManagerTest extends ArchiverTest throw new \RuntimeException('Could not init: '.$this->process->getErrorOutput()); } + $result = $this->process->execute('git config user.email "you@example.com"', $output, $this->testDir); + if ($result > 0) { + chdir($currentWorkDir); + throw new \RuntimeException('Could not config: '.$this->process->getErrorOutput()); + } + + $result = $this->process->execute('git config user.name "Your Name"', $output, $this->testDir); + if ($result > 0) { + chdir($currentWorkDir); + throw new \RuntimeException('Could not config: '.$this->process->getErrorOutput()); + } + $result = file_put_contents('composer.json', '{"name":"faker/faker", "description": "description", "license": "MIT"}'); if (false === $result) { chdir($currentWorkDir); From b86f9bf4ba73ce659dd20b8473686c1a60e17505 Mon Sep 17 00:00:00 2001 From: Felix Kiss Date: Tue, 17 Feb 2015 01:20:56 +0100 Subject: [PATCH 19/83] Update RootPackageInterface.php Fix typo --- src/Composer/Package/RootPackageInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Package/RootPackageInterface.php b/src/Composer/Package/RootPackageInterface.php index 7bee86324..7d39ff7bc 100644 --- a/src/Composer/Package/RootPackageInterface.php +++ b/src/Composer/Package/RootPackageInterface.php @@ -20,7 +20,7 @@ namespace Composer\Package; interface RootPackageInterface extends CompletePackageInterface { /** - * Returns a set of package names and theirs aliases + * Returns a set of package names and their aliases * * @return array */ From 65f8d1c247a54bd562d5ae375cc0b97c803e9ba9 Mon Sep 17 00:00:00 2001 From: Felix Kiss Date: Tue, 17 Feb 2015 02:46:15 +0100 Subject: [PATCH 20/83] Update why-are-unbound-version-constraints-a-bad-idea.md Minor text improvement --- doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md b/doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md index 183403948..56d152c82 100644 --- a/doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md +++ b/doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md @@ -14,7 +14,7 @@ compatible with the new major version of your dependency. For example instead of using `>=3.4` you should use `~3.4` which allows all versions up to `3.999` but does not include `4.0` and above. The `~` operator -works very well with libraries follow [semantic versioning](http://semver.org). +works very well with libraries following [semantic versioning](http://semver.org). **Note:** As a package maintainer, you can make the life of your users easier by providing an [alias version](../articles/aliases.md) for your development From b4698568d2575a3f3d0851a38d27cf8a5cccb706 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 17 Feb 2015 14:37:33 +0000 Subject: [PATCH 21/83] Adjust tests and fix installer code to create the pool using locked requirements and not the composer.json reqs --- src/Composer/Installer.php | 38 ++++++++++++------- ...e-installed-when-installing-from-lock.test | 8 ++-- ...aced-packages-should-not-be-installed.test | 19 +++++++++- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index e3e380f07..518f6c20d 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -33,6 +33,7 @@ use Composer\Json\JsonFile; use Composer\Package\AliasPackage; use Composer\Package\CompletePackage; use Composer\Package\Link; +use Composer\Package\LinkConstraint\EmptyConstraint; use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Package\Locker; use Composer\Package\PackageInterface; @@ -355,9 +356,6 @@ class Installer $installFromLock = false; if (!$this->update && $this->locker->isLocked()) { $installFromLock = true; - // we are removing all requirements from the root package so only the lock file is relevant for installation rules - $this->package->setRequires(array()); - $this->package->setDevRequires(array()); try { $lockedRepository = $this->locker->getLockedRepository($withDevReqs); } catch (\RuntimeException $e) { @@ -381,7 +379,7 @@ class Installer // creating repository pool $policy = $this->createPolicy(); - $pool = $this->createPool($withDevReqs); + $pool = $this->createPool($withDevReqs, $lockedRepository); $pool->addRepository($installedRepo, $aliases); if ($installFromLock) { $pool->addRepository($lockedRepository, $aliases); @@ -674,27 +672,39 @@ class Installer return array_merge($uninstOps, $operations); } - private function createPool($withDevReqs) + private function createPool($withDevReqs, RepositoryInterface $lockedRepository = null) { - $minimumStability = $this->package->getMinimumStability(); - $stabilityFlags = $this->package->getStabilityFlags(); - - if (!$this->update && $this->locker->isLocked()) { + if (!$this->update && $this->locker->isLocked()) { // install from lock $minimumStability = $this->locker->getMinimumStability(); $stabilityFlags = $this->locker->getStabilityFlags(); + + $requires = array(); + foreach ($lockedRepository->getPackages() as $package) { + $constraint = new VersionConstraint('=', $package->getVersion()); + $constraint->setPrettyString($package->getPrettyVersion()); + $requires[$package->getName()] = $constraint; + } + } else { + $minimumStability = $this->package->getMinimumStability(); + $stabilityFlags = $this->package->getStabilityFlags(); + + $requires = $this->package->getRequires(); + if ($withDevReqs) { + $requires = array_merge($requires, $this->package->getDevRequires()); + } } - $requires = $this->package->getRequires(); - if ($withDevReqs) { - $requires = array_merge($requires, $this->package->getDevRequires()); - } $rootConstraints = array(); foreach ($requires as $req => $constraint) { // skip platform requirements from the root package to avoid filtering out existing platform packages if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) { continue; } - $rootConstraints[$req] = $constraint->getConstraint(); + if ($constraint instanceof Link) { + $rootConstraints[$req] = $constraint->getConstraint(); + } else { + $rootConstraints[$req] = $constraint; + } } return new Pool($minimumStability, $stabilityFlags, $rootConstraints); diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test index 6d0602159..6e1783b58 100644 --- a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test @@ -20,8 +20,8 @@ Requiring a replaced package in a version, that is not provided by the replacing --LOCK-- { "packages": [ - { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"} }, - { "name": "foo/replaced", "version": "2.0.0" } + { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"}, "type": "library" }, + { "name": "foo/replaced", "version": "2.0.0", "type": "library" } ], "packages-dev": [], "aliases": [], @@ -35,5 +35,7 @@ Requiring a replaced package in a version, that is not provided by the replacing --RUN-- install --EXPECT-EXIT-CODE-- -2 +0 --EXPECT-- +Installing foo/original (1.0.0) +Installing foo/replaced (2.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test index 0d1ea7701..78979eeac 100644 --- a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test @@ -19,6 +19,23 @@ Requiring a replaced package in a version, that is not provided by the replacing } --RUN-- install +--EXPECT-LOCK-- +{ + "packages": [ + { "name": "foo/original", "version": "1.0.0", "replace": {"foo/replaced": "1.0.0"}, "type": "library" }, + { "name": "foo/replaced", "version": "2.0.0", "type": "library" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} --EXPECT-EXIT-CODE-- -2 +0 --EXPECT-- +Installing foo/original (1.0.0) +Installing foo/replaced (2.0.0) From 5d3c7ab6b783d3867735b0ae947bf5f880e43658 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 17 Feb 2015 14:43:09 +0000 Subject: [PATCH 22/83] Rename test files and descriptions --- ...t => replaced-packages-wrong-version-install-from-lock.test} | 2 +- ...talled.test => replaced-packages-wrong-version-install.test} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/Composer/Test/Fixtures/installer/{replaced-packages-should-not-be-installed-when-installing-from-lock.test => replaced-packages-wrong-version-install-from-lock.test} (89%) rename tests/Composer/Test/Fixtures/installer/{replaced-packages-should-not-be-installed.test => replaced-packages-wrong-version-install.test} (92%) diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install-from-lock.test similarity index 89% rename from tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test rename to tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install-from-lock.test index 6e1783b58..2721772ae 100644 --- a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed-when-installing-from-lock.test +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install-from-lock.test @@ -1,5 +1,5 @@ --TEST-- -Requiring a replaced package in a version, that is not provided by the replacing package, should result in a conflict, when installing from lock +Requiring a replaced package in a version, that is not provided by the replacing package, should install correctly (although that is not a very smart idea) also when installing from lock --COMPOSER-- { "repositories": [ diff --git a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test b/tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install.test similarity index 92% rename from tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test rename to tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install.test index 78979eeac..8971f8069 100644 --- a/tests/Composer/Test/Fixtures/installer/replaced-packages-should-not-be-installed.test +++ b/tests/Composer/Test/Fixtures/installer/replaced-packages-wrong-version-install.test @@ -1,5 +1,5 @@ --TEST-- -Requiring a replaced package in a version, that is not provided by the replacing package, should result in a conflict +Requiring a replaced package in a version, that is not provided by the replacing package, should install correctly (although that is not a very smart idea) --COMPOSER-- { "repositories": [ From 0e977e3fde3d84b98824753fde0079f2d182a7b9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 17 Feb 2015 20:06:02 +0000 Subject: [PATCH 23/83] Add more docs to config command --- src/Composer/Command/ConfigCommand.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 9773ea885..1fd5750df 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -65,6 +65,15 @@ class ConfigCommand extends Command This command allows you to edit some basic composer settings in either the local composer.json file or the global config.json file. +To set a config setting: + + %command.full_name% bin-dir bin/ + +To read a config setting: + + %command.full_name% bin-dir + Outputs: bin + To edit the global config.json file: %command.full_name% --global @@ -73,7 +82,15 @@ To add a repository: %command.full_name% repositories.foo vcs http://bar.com -You can add a repository to the global config.json file by passing in the +To remove a repository (repo is a short alias for repositories): + + %command.full_name% --unset repo.foo + +To disable packagist: + + %command.full_name% repo.packagist false + +You can alter repositories in the global config.json file by passing in the --global option. To edit the file in an external editor: From b2b9688c9281503f8dcd6e90cc5c9e51b698e233 Mon Sep 17 00:00:00 2001 From: Nimit Kalra Date: Wed, 18 Feb 2015 15:06:36 -0600 Subject: [PATCH 24/83] Conform with Symfony Coding Standards According to Symfony Coding Standards, a single space must be added around binary operators excluding the concatenation operator. "Add a single space around binary operators (==, &&, ...), with the exception of the concatenation (.) operator" (http://symfony.com/doc/current/contributing/code/standards.html) --- src/Composer/Console/HtmlOutputFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Console/HtmlOutputFormatter.php b/src/Composer/Console/HtmlOutputFormatter.php index 56652bb69..8a79dba08 100644 --- a/src/Composer/Console/HtmlOutputFormatter.php +++ b/src/Composer/Console/HtmlOutputFormatter.php @@ -83,6 +83,6 @@ class HtmlOutputFormatter extends OutputFormatter } } - return $out . '">'.$matches[2].''; + return $out.'">'.$matches[2].''; } } From 3dd93c91b80036c5e6e17790239e8a07a4fe384a Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Fri, 6 Feb 2015 15:23:13 +0100 Subject: [PATCH 25/83] TableHelper is deprecated, switched to Table --- src/Composer/Command/LicensesCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 8ab9d94b4..757de6d87 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -18,7 +18,7 @@ use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Composer\Package\PackageInterface; use Composer\Repository\RepositoryInterface; -use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -73,9 +73,9 @@ EOT $output->writeln('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').''); $output->writeln('Dependencies:'); - $table = $this->getHelperSet()->get('table'); - $table->setLayout(TableHelper::LAYOUT_BORDERLESS); - $table->setHorizontalBorderChar(''); + $table = new Table($output); + $table->setStyle('borderless'); + $table->getStyle()->setHorizontalBorderChar(''); foreach ($packages as $package) { $table->addRow(array( $package->getPrettyName(), From 85182cf7e198e844f0d1c50bbdac3c5253a6a13d Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Thu, 19 Feb 2015 13:56:53 +0100 Subject: [PATCH 26/83] Update dependency version constraint --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9fca7d74c..bf278f478 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php": ">=5.3.2", "justinrainbow/json-schema": "~1.3", "seld/jsonlint": "~1.0", - "symfony/console": "~2.3", + "symfony/console": "~2.5", "symfony/finder": "~2.2", "symfony/process": "~2.1" }, diff --git a/composer.lock b/composer.lock index 7d28fcb09..c6ba9d836 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2bc9cc8aa706b68d611d7058e4eb8de7", + "hash": "ba903feb0f02e7916ecbe23f857bcce4", "packages": [ { "name": "justinrainbow/json-schema", From b91be79137b600e0f88cddc135d5828c5f6a53ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 21 Feb 2015 11:08:35 +0100 Subject: [PATCH 27/83] Update PHPUnit version to get prophecy --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9fca7d74c..57a0264ce 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "symfony/process": "~2.1" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.5" }, "suggest": { "ext-zip": "Enabling the zip extension allows you to unzip archives, and allows gzip compression of all internet traffic", From 9c58fd725f778d968feaa8bd62242da5213765a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 21 Feb 2015 11:08:47 +0100 Subject: [PATCH 28/83] Update deps --- composer.lock | 296 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 228 insertions(+), 68 deletions(-) diff --git a/composer.lock b/composer.lock index 7d28fcb09..a2497e43b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2bc9cc8aa706b68d611d7058e4eb8de7", + "hash": "7970fc5134ce2913f3efb9c56be43b3c", "packages": [ { "name": "justinrainbow/json-schema", @@ -74,16 +74,16 @@ }, { "name": "seld/jsonlint", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35" + "reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/a7bc2ec9520ad15382292591b617c43bdb1fec35", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/863ae85c6d3ef60ca49cb12bd051c4a0648c40c4", + "reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4", "shasum": "" }, "require": { @@ -116,21 +116,21 @@ "parser", "validator" ], - "time": "2014-09-05 15:36:20" + "time": "2015-01-04 21:18:15" }, { "name": "symfony/console", - "version": "v2.6.1", + "version": "v2.6.4", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8" + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8", + "url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", "shasum": "" }, "require": { @@ -173,21 +173,21 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2014-12-02 20:19:20" + "time": "2015-01-25 04:39:26" }, { "name": "symfony/finder", - "version": "v2.6.1", + "version": "v2.6.4", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721" + "reference": "16513333bca64186c01609961a2bb1b95b5e1355" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", + "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355", "shasum": "" }, "require": { @@ -220,21 +220,21 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2014-12-02 20:19:20" + "time": "2015-01-03 08:01:59" }, { "name": "symfony/process", - "version": "v2.6.1", + "version": "v2.6.4", "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/Process.git", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a" + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a", + "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", "shasum": "" }, "require": { @@ -267,7 +267,7 @@ ], "description": "Symfony Process Component", "homepage": "http://symfony.com", - "time": "2014-12-02 20:19:20" + "time": "2015-01-25 04:39:26" } ], "packages-dev": [ @@ -326,17 +326,125 @@ "time": "2014-10-13 12:58:55" }, { - "name": "phpunit/php-code-coverage", - "version": "2.0.14", + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94" + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca158276c1200cc27f5409a5e338486bc0b4fc94", - "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "phpdocumentor/reflection-docblock": "~2.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "http://phpspec.org", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2014-11-17 16:23:49" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.0.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67", "shasum": "" }, "require": { @@ -349,7 +457,7 @@ }, "require-dev": { "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4.1" + "phpunit/phpunit": "~4" }, "suggest": { "ext-dom": "*", @@ -368,9 +476,6 @@ ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], "license": [ "BSD-3-Clause" ], @@ -388,7 +493,7 @@ "testing", "xunit" ], - "time": "2014-12-26 13:28:33" + "time": "2015-01-24 10:06:35" }, { "name": "phpunit/php-file-iterator", @@ -525,16 +630,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "f8d5d08c56de5cfd592b3340424a81733259a876" + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876", - "reference": "f8d5d08c56de5cfd592b3340424a81733259a876", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", "shasum": "" }, "require": { @@ -547,7 +652,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -570,20 +675,20 @@ "keywords": [ "tokenizer" ], - "time": "2014-08-31 06:12:13" + "time": "2015-01-17 09:51:32" }, { "name": "phpunit/phpunit", - "version": "4.4.1", + "version": "4.5.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a" + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6a5e49a86ce5e33b8d0657abe145057fc513543a", - "reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5b578d3865a9128b9c209b011fda6539ec06e7a5", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5", "shasum": "" }, "require": { @@ -593,15 +698,16 @@ "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", + "phpspec/prophecy": "~1.3.1", "phpunit/php-code-coverage": "~2.0", "phpunit/php-file-iterator": "~1.3.2", "phpunit/php-text-template": "~1.2", "phpunit/php-timer": "~1.0.2", "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.0", + "sebastian/comparator": "~1.1", "sebastian/diff": "~1.1", - "sebastian/environment": "~1.1", - "sebastian/exporter": "~1.0", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", "sebastian/global-state": "~1.0", "sebastian/version": "~1.0", "symfony/yaml": "~2.0" @@ -615,7 +721,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4.x-dev" + "dev-master": "4.5.x-dev" } }, "autoload": { @@ -641,7 +747,7 @@ "testing", "xunit" ], - "time": "2014-12-28 07:57:05" + "time": "2015-02-05 15:51:19" }, { "name": "phpunit/phpunit-mock-objects", @@ -700,25 +806,25 @@ }, { "name": "sebastian/comparator", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "c484a80f97573ab934e37826dba0135a3301b26a" + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a", - "reference": "c484a80f97573ab934e37826dba0135a3301b26a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", "shasum": "" }, "require": { "php": ">=5.3.3", - "sebastian/diff": "~1.1", - "sebastian/exporter": "~1.0" + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" }, "require-dev": { - "phpunit/phpunit": "~4.1" + "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { @@ -760,7 +866,7 @@ "compare", "equality" ], - "time": "2014-11-16 21:32:38" + "time": "2015-01-29 16:28:08" }, { "name": "sebastian/diff", @@ -866,28 +972,29 @@ }, { "name": "sebastian/exporter", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0" + "reference": "84839970d05254c73cde183a721c7af13aede943" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0", - "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -927,7 +1034,7 @@ "export", "exporter" ], - "time": "2014-09-10 00:51:36" + "time": "2015-01-27 07:23:06" }, { "name": "sebastian/global-state", @@ -980,6 +1087,59 @@ ], "time": "2014-10-06 09:23:50" }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, { "name": "sebastian/version", "version": "1.0.4", @@ -1017,17 +1177,17 @@ }, { "name": "symfony/yaml", - "version": "v2.6.1", + "version": "v2.6.4", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20" + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8", "shasum": "" }, "require": { @@ -1060,7 +1220,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2014-12-02 20:19:20" + "time": "2015-01-25 04:39:26" } ], "aliases": [], From 85955d82a6b618f7488ec18221d1205941f5f069 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Mon, 23 Feb 2015 09:57:54 +0100 Subject: [PATCH 29/83] Raise timeout to 5 minutes --- tests/Composer/Test/AllFunctionalTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index 4a23c5717..6670cc4fa 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -89,7 +89,7 @@ class AllFunctionalTest extends \PHPUnit_Framework_TestCase putenv('COMPOSER_HOME='.$this->testDir.'home'); $cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN']; - $proc = new Process($cmd, __DIR__.'/Fixtures/functional'); + $proc = new Process($cmd, __DIR__.'/Fixtures/functional', null, null, 300); $exitcode = $proc->run(); if (isset($testData['EXPECT'])) { From 3efed220a6c9fd6e4a13ea806879e124941c9fc7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 23 Feb 2015 15:31:54 +0000 Subject: [PATCH 30/83] Clean up event dispatching code and make package events extend installer events --- src/Composer/Command/CreateProjectCommand.php | 4 +- src/Composer/Command/RunScriptCommand.php | 18 +-- src/Composer/Command/StatusCommand.php | 4 +- .../EventDispatcher/EventDispatcher.php | 51 ++++---- src/Composer/Installer.php | 20 +-- src/Composer/Installer/InstallerEvent.php | 17 ++- src/Composer/Installer/PackageEvent.php | 69 +++++++++++ src/Composer/Installer/PackageEvents.php | 75 ++++++++++++ src/Composer/Script/CommandEvent.php | 2 +- src/Composer/Script/PackageEvent.php | 37 +----- src/Composer/Script/ScriptEvents.php | 114 ++++++++++-------- .../EventDispatcher/EventDispatcherTest.php | 16 +-- .../Test/Installer/InstallerEventTest.php | 3 +- 13 files changed, 279 insertions(+), 151 deletions(-) create mode 100644 src/Composer/Installer/PackageEvent.php create mode 100644 src/Composer/Installer/PackageEvents.php diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 0242afcd3..7bf3fed15 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -149,7 +149,7 @@ EOT if ($noScripts === false) { // dispatch event - $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages); + $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages); } $rootPackageConfig = $composer->getConfig(); @@ -217,7 +217,7 @@ EOT if ($noScripts === false) { // dispatch event - $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages); + $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages); } chdir($oldCwd); diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index 91a9b2abe..7e9fe6845 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -27,7 +27,7 @@ class RunScriptCommand extends Command /** * @var array Array with command events */ - protected $commandEvents = array( + protected $scriptEvents = array( ScriptEvents::PRE_INSTALL_CMD, ScriptEvents::POST_INSTALL_CMD, ScriptEvents::PRE_UPDATE_CMD, @@ -35,17 +35,11 @@ class RunScriptCommand extends Command ScriptEvents::PRE_STATUS_CMD, ScriptEvents::POST_STATUS_CMD, ScriptEvents::POST_ROOT_PACKAGE_INSTALL, - ScriptEvents::POST_CREATE_PROJECT_CMD - ); - - /** - * @var array Array with script events - */ - protected $scriptEvents = array( + ScriptEvents::POST_CREATE_PROJECT_CMD, ScriptEvents::PRE_ARCHIVE_CMD, ScriptEvents::POST_ARCHIVE_CMD, ScriptEvents::PRE_AUTOLOAD_DUMP, - ScriptEvents::POST_AUTOLOAD_DUMP + ScriptEvents::POST_AUTOLOAD_DUMP, ); protected function configure() @@ -78,7 +72,7 @@ EOT } $script = $input->getArgument('script'); - if (!in_array($script, $this->commandEvents) && !in_array($script, $this->scriptEvents)) { + if (!in_array($script, $this->scriptEvents)) { if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) { throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script)); } @@ -98,10 +92,6 @@ EOT $args = $input->getArgument('args'); - if (in_array($script, $this->commandEvents)) { - return $composer->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args); - } - return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args); } diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index 65662c048..e458c8fb9 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -57,7 +57,7 @@ EOT $im = $composer->getInstallationManager(); // Dispatch pre-status-command - $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::PRE_STATUS_CMD, true); + $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true); $errors = array(); @@ -98,7 +98,7 @@ EOT } // Dispatch post-status-command - $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_STATUS_CMD, true); + $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true); return $errors ? 1 : 0; } diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index dff5456e1..71fa01a41 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -21,7 +21,6 @@ use Composer\Composer; use Composer\DependencyResolver\Operation\OperationInterface; use Composer\Repository\CompositeRepository; use Composer\Script; -use Composer\Script\CommandEvent; use Composer\Script\PackageEvent; use Composer\Util\ProcessExecutor; @@ -95,36 +94,28 @@ class EventDispatcher /** * Dispatch a package event. * - * @param string $eventName The constant in ScriptEvents - * @param boolean $devMode Whether or not we are in dev mode - * @param OperationInterface $operation The package being installed/updated/removed - * @return int return code of the executed script if any, for php scripts a false return - * value is changed to 1, anything else to 0 - */ - public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation) - { - return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation)); - } - - /** - * Dispatch a command event. + * @param string $eventName The constant in PackageEvents + * @param bool $devMode Whether or not we are in dev mode + * @param PolicyInterface $policy The policy + * @param Pool $pool The pool + * @param CompositeRepository $installedRepo The installed repository + * @param Request $request The request + * @param array $operations The list of operations + * @param OperationInterface $operation The package being installed/updated/removed * - * @param string $eventName The constant in ScriptEvents - * @param boolean $devMode Whether or not we are in dev mode - * @param array $additionalArgs Arguments passed by the user - * @param array $flags Optional flags to pass data not as argument - * @return int return code of the executed script if any, for php scripts a false return - * value is changed to 1, anything else to 0 + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 */ - public function dispatchCommandEvent($eventName, $devMode, $additionalArgs = array(), $flags = array()) + public function dispatchPackageEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation) { - return $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags)); + return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations, $operation)); } /** * Dispatch a installer event. * * @param string $eventName The constant in InstallerEvents + * @param bool $devMode Whether or not we are in dev mode * @param PolicyInterface $policy The policy * @param Pool $pool The pool * @param CompositeRepository $installedRepo The installed repository @@ -134,9 +125,9 @@ class EventDispatcher * @return int return code of the executed script if any, for php scripts a false return * value is changed to 1, anything else to 0 */ - public function dispatchInstallerEvent($eventName, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array()) + public function dispatchInstallerEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array()) { - return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $policy, $pool, $installedRepo, $request, $operations)); + return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations)); } /** @@ -232,8 +223,18 @@ class EventDispatcher $expected = $typehint->getName(); + // BC support if (!$event instanceof $expected && $expected === 'Composer\Script\CommandEvent') { - $event = new CommandEvent($event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments()); + $event = new \Composer\Script\CommandEvent( + $event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments() + ); + } + if (!$event instanceof $expected && $expected === 'Composer\Script\PackageEvent') { + $event = new \Composer\Script\PackageEvent( + $event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), + $event->getPolicy(), $event->getPool(), $event->getInstalledRepo(), $event->getRequest(), + $event->getOperations(), $event->getOperation() + ); } return $event; diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 518f6c20d..d852cc589 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -192,7 +192,7 @@ class Installer if ($this->runScripts) { // dispatch pre event $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; - $this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode); + $this->eventDispatcher->dispatchScript($eventName, $this->devMode); } $this->downloadManager->setPreferSource($this->preferSource); @@ -289,10 +289,10 @@ class Installer $request->install($link->getTarget(), $link->getConstraint()); } - $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request); + $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo); $ops = $solver->solve($request, $this->ignorePlatformReqs); - $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $ops); + $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops); foreach ($ops as $op) { if ($op->getJobType() === 'uninstall') { $devPackages[] = $op->getPackage(); @@ -334,7 +334,7 @@ class Installer if ($this->runScripts) { // dispatch post event $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; - $this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode); + $this->eventDispatcher->dispatchScript($eventName, $this->devMode); } $vendorDir = $this->config->get('vendor-dir'); @@ -498,11 +498,11 @@ class Installer $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links'); // solve dependencies - $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request); + $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo); try { $operations = $solver->solve($request, $this->ignorePlatformReqs); - $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $operations); + $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations); } catch (SolverProblemsException $e) { $this->io->write('Your requirements could not be resolved to an installable set of packages.'); $this->io->write($e->getMessage()); @@ -562,9 +562,9 @@ class Installer } } - $event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType()); + $event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { - $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation); + $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation); } // output non-alias ops in dry run, output alias ops in debug verbosity @@ -595,9 +595,9 @@ class Installer } } - $event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType()); + $event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { - $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation); + $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation); } if (!$this->dryRun) { diff --git a/src/Composer/Installer/InstallerEvent.php b/src/Composer/Installer/InstallerEvent.php index a9f5a728a..87153bd51 100644 --- a/src/Composer/Installer/InstallerEvent.php +++ b/src/Composer/Installer/InstallerEvent.php @@ -38,6 +38,11 @@ class InstallerEvent extends Event */ private $io; + /** + * @var bool + */ + private $devMode; + /** * @var PolicyInterface */ @@ -69,18 +74,20 @@ class InstallerEvent extends Event * @param string $eventName * @param Composer $composer * @param IOInterface $io + * @param bool $devMode * @param PolicyInterface $policy * @param Pool $pool * @param CompositeRepository $installedRepo * @param Request $request * @param OperationInterface[] $operations */ - public function __construct($eventName, Composer $composer, IOInterface $io, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array()) + public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array()) { parent::__construct($eventName); $this->composer = $composer; $this->io = $io; + $this->devMode = $devMode; $this->policy = $policy; $this->pool = $pool; $this->installedRepo = $installedRepo; @@ -104,6 +111,14 @@ class InstallerEvent extends Event return $this->io; } + /** + * @return bool + */ + public function isDevMode() + { + return $this->devMode; + } + /** * @return PolicyInterface */ diff --git a/src/Composer/Installer/PackageEvent.php b/src/Composer/Installer/PackageEvent.php new file mode 100644 index 000000000..527a5b6a2 --- /dev/null +++ b/src/Composer/Installer/PackageEvent.php @@ -0,0 +1,69 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Installer; + +use Composer\Composer; +use Composer\IO\IOInterface; +use Composer\DependencyResolver\Operation\OperationInterface; + +/** + * The Package Event. + * + * @author Jordi Boggiano + */ +class PackageEvent extends InstallerEvent +{ + /** + * @var OperationInterface The package instance + */ + private $operation; + + /** + * Constructor. + * + * @param string $eventName + * @param Composer $composer + * @param IOInterface $io + * @param bool $devMode + * @param PolicyInterface $policy + * @param Pool $pool + * @param CompositeRepository $installedRepo + * @param Request $request + * @param OperationInterface[] $operations + * @param OperationInterface $operation + */ + public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation) + { + parent::__construct($eventName); + + $this->composer = $composer; + $this->io = $io; + $this->devMode = $devMode; + $this->policy = $policy; + $this->pool = $pool; + $this->installedRepo = $installedRepo; + $this->request = $request; + $this->operations = $operations; + $this->operation = $operation; + } + + /** + * Returns the package instance. + * + * @return OperationInterface + */ + public function getOperation() + { + return $this->operation; + } +} diff --git a/src/Composer/Installer/PackageEvents.php b/src/Composer/Installer/PackageEvents.php new file mode 100644 index 000000000..637b7fb45 --- /dev/null +++ b/src/Composer/Installer/PackageEvents.php @@ -0,0 +1,75 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Installer; + +/** + * Package Events. + * + * @author Jordi Boggiano + */ +class PackageEvents +{ + /** + * The PRE_PACKAGE_INSTALL event occurs before a package is installed. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const PRE_PACKAGE_INSTALL = 'pre-package-install'; + + /** + * The POST_PACKAGE_INSTALL event occurs after a package is installed. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const POST_PACKAGE_INSTALL = 'post-package-install'; + + /** + * The PRE_PACKAGE_UPDATE event occurs before a package is updated. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const PRE_PACKAGE_UPDATE = 'pre-package-update'; + + /** + * The POST_PACKAGE_UPDATE event occurs after a package is updated. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const POST_PACKAGE_UPDATE = 'post-package-update'; + + /** + * The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall'; + + /** + * The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @var string + */ + const POST_PACKAGE_UNINSTALL = 'post-package-uninstall'; +} diff --git a/src/Composer/Script/CommandEvent.php b/src/Composer/Script/CommandEvent.php index 48ea2246a..84c52008c 100644 --- a/src/Composer/Script/CommandEvent.php +++ b/src/Composer/Script/CommandEvent.php @@ -15,7 +15,7 @@ namespace Composer\Script; /** * The Command Event. * - * @author François Pluchino + * @deprecated use Composer\Script\Event instead */ class CommandEvent extends Event { diff --git a/src/Composer/Script/PackageEvent.php b/src/Composer/Script/PackageEvent.php index 735de0021..531b86a40 100644 --- a/src/Composer/Script/PackageEvent.php +++ b/src/Composer/Script/PackageEvent.php @@ -12,44 +12,13 @@ namespace Composer\Script; -use Composer\Composer; -use Composer\IO\IOInterface; -use Composer\DependencyResolver\Operation\OperationInterface; +use Composer\Installer\PackageEvent as BasePackageEvent; /** * The Package Event. * - * @author Jordi Boggiano + * @deprecated Use Composer\Installer\PackageEvent instead */ -class PackageEvent extends Event +class PackageEvent extends BasePackageEvent { - /** - * @var OperationInterface The package instance - */ - private $operation; - - /** - * Constructor. - * - * @param string $name The event name - * @param Composer $composer The composer object - * @param IOInterface $io The IOInterface object - * @param boolean $devMode Whether or not we are in dev mode - * @param OperationInterface $operation The operation object - */ - public function __construct($name, Composer $composer, IOInterface $io, $devMode, OperationInterface $operation) - { - parent::__construct($name, $composer, $io, $devMode); - $this->operation = $operation; - } - - /** - * Returns the package instance. - * - * @return OperationInterface - */ - public function getOperation() - { - return $this->operation; - } } diff --git a/src/Composer/Script/ScriptEvents.php b/src/Composer/Script/ScriptEvents.php index 616b2b97e..65baf2cc4 100644 --- a/src/Composer/Script/ScriptEvents.php +++ b/src/Composer/Script/ScriptEvents.php @@ -74,59 +74,7 @@ class ScriptEvents */ const POST_STATUS_CMD = 'post-status-cmd'; - /** - * The PRE_PACKAGE_INSTALL event occurs before a package is installed. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const PRE_PACKAGE_INSTALL = 'pre-package-install'; - - /** - * The POST_PACKAGE_INSTALL event occurs after a package is installed. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const POST_PACKAGE_INSTALL = 'post-package-install'; - - /** - * The PRE_PACKAGE_UPDATE event occurs before a package is updated. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const PRE_PACKAGE_UPDATE = 'pre-package-update'; - - /** - * The POST_PACKAGE_UPDATE event occurs after a package is updated. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const POST_PACKAGE_UPDATE = 'post-package-update'; - - /** - * The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall'; - - /** - * The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled. - * - * The event listener method receives a Composer\Script\PackageEvent instance. - * - * @var string - */ - const POST_PACKAGE_UNINSTALL = 'post-package-uninstall'; + /** Deprecated constants below */ /** * The PRE_AUTOLOAD_DUMP event occurs before the autoload file is generated. @@ -182,4 +130,64 @@ class ScriptEvents * @var string */ const POST_ARCHIVE_CMD = 'post-archive-cmd'; + + /** + * The PRE_PACKAGE_INSTALL event occurs before a package is installed. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::PRE_PACKAGE_INSTALL instead. + * @var string + */ + const PRE_PACKAGE_INSTALL = 'pre-package-install'; + + /** + * The POST_PACKAGE_INSTALL event occurs after a package is installed. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::POST_PACKAGE_INSTALL instead. + * @var string + */ + const POST_PACKAGE_INSTALL = 'post-package-install'; + + /** + * The PRE_PACKAGE_UPDATE event occurs before a package is updated. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::PRE_PACKAGE_UPDATE instead. + * @var string + */ + const PRE_PACKAGE_UPDATE = 'pre-package-update'; + + /** + * The POST_PACKAGE_UPDATE event occurs after a package is updated. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::POST_PACKAGE_UPDATE instead. + * @var string + */ + const POST_PACKAGE_UPDATE = 'post-package-update'; + + /** + * The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::PRE_PACKAGE_UNINSTALL instead. + * @var string + */ + const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall'; + + /** + * The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled. + * + * The event listener method receives a Composer\Script\PackageEvent instance. + * + * @deprecated Use Composer\Installer\PackageEvents::POST_PACKAGE_UNINSTALL instead. + * @var string + */ + const POST_PACKAGE_UNINSTALL = 'post-package-uninstall'; } diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php index aaf8b6267..c750e82a9 100644 --- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php +++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php @@ -36,7 +36,7 @@ class EventDispatcherTest extends TestCase ->method('write') ->with('Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception'); - $dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false); + $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); } public function testDispatcherCanConvertScriptEventToCommandEventForListener() @@ -48,7 +48,7 @@ class EventDispatcherTest extends TestCase $this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false)); } - + public function testDispatcherDoesNotAttemptConversionForListenerWithoutTypehint() { $io = $this->getMock('Composer\IO\IOInterface'); @@ -85,7 +85,7 @@ class EventDispatcherTest extends TestCase ->with($command) ->will($this->returnValue(0)); - $dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false); + $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); } public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack() @@ -121,7 +121,7 @@ class EventDispatcherTest extends TestCase ->with('Composer\Test\EventDispatcher\EventDispatcherTest', 'someMethod') ->will($this->returnValue(true)); - $dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false); + $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); } private function getDispatcherStubForListenersTest($listeners, $io) @@ -167,7 +167,7 @@ class EventDispatcherTest extends TestCase ->will($this->returnValue($listener)); ob_start(); - $dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false); + $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); $this->assertEquals('foo', trim(ob_get_clean())); } @@ -193,7 +193,7 @@ class EventDispatcherTest extends TestCase ->with($this->equalTo('Script '.$code.' handling the post-install-cmd event returned with an error')); $this->setExpectedException('RuntimeException'); - $dispatcher->dispatchCommandEvent(ScriptEvents::POST_INSTALL_CMD, false); + $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); } public function testDispatcherInstallerEvents() @@ -217,8 +217,8 @@ class EventDispatcherTest extends TestCase $installedRepo = $this->getMockBuilder('Composer\Repository\CompositeRepository')->disableOriginalConstructor()->getMock(); $request = $this->getMockBuilder('Composer\DependencyResolver\Request')->disableOriginalConstructor()->getMock(); - $dispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request); - $dispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, array()); + $dispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, true, $policy, $pool, $installedRepo, $request); + $dispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, true, $policy, $pool, $installedRepo, $request, array()); } public static function call() diff --git a/tests/Composer/Test/Installer/InstallerEventTest.php b/tests/Composer/Test/Installer/InstallerEventTest.php index 7cd63f6b5..1489f5f0e 100644 --- a/tests/Composer/Test/Installer/InstallerEventTest.php +++ b/tests/Composer/Test/Installer/InstallerEventTest.php @@ -25,11 +25,12 @@ class InstallerEventTest extends \PHPUnit_Framework_TestCase $installedRepo = $this->getMockBuilder('Composer\Repository\CompositeRepository')->disableOriginalConstructor()->getMock(); $request = $this->getMockBuilder('Composer\DependencyResolver\Request')->disableOriginalConstructor()->getMock(); $operations = array($this->getMock('Composer\DependencyResolver\Operation\OperationInterface')); - $event = new InstallerEvent('EVENT_NAME', $composer, $io, $policy, $pool, $installedRepo, $request, $operations); + $event = new InstallerEvent('EVENT_NAME', $composer, $io, true, $policy, $pool, $installedRepo, $request, $operations); $this->assertSame('EVENT_NAME', $event->getName()); $this->assertInstanceOf('Composer\Composer', $event->getComposer()); $this->assertInstanceOf('Composer\IO\IOInterface', $event->getIO()); + $this->assertTrue($event->isDevMode()); $this->assertInstanceOf('Composer\DependencyResolver\PolicyInterface', $event->getPolicy()); $this->assertInstanceOf('Composer\DependencyResolver\Pool', $event->getPool()); $this->assertInstanceOf('Composer\Repository\CompositeRepository', $event->getInstalledRepo()); From 074a748675a940f42c1a9ddc27777c56427c19c8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 23 Feb 2015 16:35:54 +0000 Subject: [PATCH 31/83] missing use statements :s --- src/Composer/Installer/PackageEvent.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Composer/Installer/PackageEvent.php b/src/Composer/Installer/PackageEvent.php index 527a5b6a2..2b81d336b 100644 --- a/src/Composer/Installer/PackageEvent.php +++ b/src/Composer/Installer/PackageEvent.php @@ -15,6 +15,11 @@ namespace Composer\Installer; use Composer\Composer; use Composer\IO\IOInterface; use Composer\DependencyResolver\Operation\OperationInterface; +use Composer\DependencyResolver\PolicyInterface; +use Composer\DependencyResolver\Pool; +use Composer\DependencyResolver\Request; +use Composer\EventDispatcher\Event; +use Composer\Repository\CompositeRepository; /** * The Package Event. From 09da587ee2aabf3bffc85dda97f2aaf1246fc8b4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 23 Feb 2015 16:37:50 +0000 Subject: [PATCH 32/83] Forward args --- src/Composer/Installer/PackageEvent.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Composer/Installer/PackageEvent.php b/src/Composer/Installer/PackageEvent.php index 2b81d336b..e1c5e6080 100644 --- a/src/Composer/Installer/PackageEvent.php +++ b/src/Composer/Installer/PackageEvent.php @@ -49,16 +49,8 @@ class PackageEvent extends InstallerEvent */ public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation) { - parent::__construct($eventName); + parent::__construct($eventName, $composer, $io, $devMode, $policy, $pool, $installedRepo, $request, $operations); - $this->composer = $composer; - $this->io = $io; - $this->devMode = $devMode; - $this->policy = $policy; - $this->pool = $pool; - $this->installedRepo = $installedRepo; - $this->request = $request; - $this->operations = $operations; $this->operation = $operation; } From 01476214da5a430242e2641730b88db1e692fe9a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Feb 2015 12:49:14 +0000 Subject: [PATCH 33/83] Tweak satis/toran/packagist docs --- doc/05-repositories.md | 14 ++++++++------ .../handling-private-packages-with-satis.md | 10 ++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 80d15c561..2dd5e24d5 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -533,10 +533,9 @@ There are a few tools that can help you create a `composer` repository. ### Packagist The underlying application used by packagist is open source. This means that you -can just install your own copy of packagist, re-brand, and use it. It's really -quite straight-forward to do. However due to its size and complexity, for most -small and medium sized companies willing to track a few packages will be better -off using Satis. +can technically install your own copy of packagist. However it is not a +supported use case and changes will happen without caring for third parties +using the code. Packagist is a Symfony2 application, and it is [available on GitHub](https://github.com/composer/packagist). It uses composer internally and @@ -544,8 +543,11 @@ acts as a proxy between VCS repositories and the composer users. It holds a list of all VCS packages, periodically re-crawls them, and exposes them as a composer repository. -To set your own copy, simply follow the instructions from the [packagist -github repository](https://github.com/composer/packagist). +### Toran Proxy + +[Toran Proxy](https://toranproxy.com/) is a web app much like Packagist but +providing private package hosting as well as mirroring/proxying of GitHub and packagist.org. Check its homepage and the [Satis/Toran Proxy article](articles/handling-private-packages-with-satis.md) +for more information. ### Satis diff --git a/doc/articles/handling-private-packages-with-satis.md b/doc/articles/handling-private-packages-with-satis.md index 5fce5377b..832640b85 100644 --- a/doc/articles/handling-private-packages-with-satis.md +++ b/doc/articles/handling-private-packages-with-satis.md @@ -6,9 +6,15 @@ # Toran Proxy -[Toran Proxy](https://toranproxy.com/) is a commercial alternative to Satis offering professional support as well as a web UI to manage everything and a better integration with Composer. +[Toran Proxy](https://toranproxy.com/) is a commercial alternative to Satis +offering professional support as well as a web UI to manage everything and a +better integration with Composer. It also provides proxying/mirroring for git +repos and package zip files which makes installs faster and independent from +third party systems. -Toran's revenue is also used to pay for Composer and Packagist development and hosting so using it is a good way to support open source financially. You can find more information about how to set it up and use it on the [Toran Proxy](https://toranproxy.com/) website. +Toran's revenue is also used to pay for Composer and Packagist development and +hosting so using it is a good way to support open source financially. You can +find more information about how to set it up and use it on the [Toran Proxy](https://toranproxy.com/) website. # Satis From 3cff4a3bb977c2ba9a09204690da128c7dceb092 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Feb 2015 13:07:28 +0000 Subject: [PATCH 34/83] Check for homepages in local repo first if available to make the home command faster --- src/Composer/Command/HomeCommand.php | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Composer/Command/HomeCommand.php b/src/Composer/Command/HomeCommand.php index 7dd8113cb..5ea193d5c 100644 --- a/src/Composer/Command/HomeCommand.php +++ b/src/Composer/Command/HomeCommand.php @@ -57,10 +57,16 @@ EOT */ protected function execute(InputInterface $input, OutputInterface $output) { - $repo = $this->initializeRepo(); + $repos = $this->initializeRepos(); $return = 0; foreach ($input->getArgument('packages') as $packageName) { + foreach ($repos as $repo) { + $package = $this->getPackage($repo, $packageName); + if ($package instanceof CompletePackageInterface) { + break; + } + } $package = $this->getPackage($repo, $packageName); if (!$package instanceof CompletePackageInterface) { @@ -144,21 +150,25 @@ EOT } /** - * Initializes the repo + * Initializes repositories * - * @return CompositeRepository + * Returns an array of repos in order they should be checked in + * + * @return RepositoryInterface[] */ - private function initializeRepo() + private function initializeRepos() { $composer = $this->getComposer(false); if ($composer) { - $repo = new CompositeRepository($composer->getRepositoryManager()->getRepositories()); - } else { - $defaultRepos = Factory::createDefaultRepositories($this->getIO()); - $repo = new CompositeRepository($defaultRepos); + return array( + $composer->getRepositoryManager()->getLocalRepository(), + new CompositeRepository($composer->getRepositoryManager()->getRepositories()) + ); } - return $repo; + $defaultRepos = Factory::createDefaultRepositories($this->getIO()); + + return array(new CompositeRepository($defaultRepos)); } } From 0b4a9235f494134e1e0d1cc66c95efade9f8a926 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Feb 2015 14:22:54 +0000 Subject: [PATCH 35/83] CS fixes --- src/Composer/Autoload/AutoloadGenerator.php | 2 +- src/Composer/Installer.php | 3 --- src/Composer/Package/Loader/ArrayLoader.php | 2 +- src/Composer/Package/Loader/RootPackageLoader.php | 4 ++-- src/Composer/Package/Loader/ValidatingArrayLoader.php | 2 +- src/Composer/Repository/Vcs/GitDriver.php | 2 +- tests/Composer/Test/Autoload/AutoloadGeneratorTest.php | 1 + tests/Composer/Test/IO/ConsoleIOTest.php | 3 ++- tests/Composer/Test/InstallerTest.php | 3 +-- tests/Composer/Test/Mock/FactoryMock.php | 1 - .../Composer/Test/Package/Loader/RootPackageLoaderTest.php | 6 ++++-- tests/Composer/Test/Util/GitHubTest.php | 1 + 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index c88c34b41..3326861c1 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -383,7 +383,7 @@ EOF; } if (!$filesCode) { - return FALSE; + return false; } return <<versionParser->parseNumericAliasPrefix($sourceBranch)) + if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch)) && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch)) && (stripos($targetPrefix, $sourcePrefix) !== 0) ) { diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 90c8ce3b9..6fe8899fb 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -279,13 +279,13 @@ class RootPackageLoader extends ArrayLoader $length = PHP_INT_MAX; $nonFeatureBranches = ''; - if(!empty($config['non-feature-branches'])) { + if (!empty($config['non-feature-branches'])) { $nonFeatureBranches = implode('|', $config['non-feature-branches']); } foreach ($branches as $candidate) { // return directly, if branch is configured to be non-feature branch - if($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) { + if ($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) { return $version; } diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index 9a6f4dd32..65655c4a6 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -256,7 +256,7 @@ class ValidatingArrayLoader implements LoaderInterface } // If using numeric aliases ensure the alias is a valid subversion - if(($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch)) + if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch)) && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch)) && (stripos($targetPrefix, $sourcePrefix) !== 0) ) { diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index 298639bc0..a859a6869 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -242,7 +242,7 @@ class GitDriver extends VcsDriver } $process = new ProcessExecutor($io); - if($process->execute('git ls-remote --heads ' . ProcessExecutor::escape($url), $output) === 0) { + if ($process->execute('git ls-remote --heads ' . ProcessExecutor::escape($url), $output) === 0) { return true; } diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 2ad1e4729..05b89e4d5 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -106,6 +106,7 @@ class AutoloadGeneratorTest extends TestCase $ret = $ret(); } } + return $ret; })); diff --git a/tests/Composer/Test/IO/ConsoleIOTest.php b/tests/Composer/Test/IO/ConsoleIOTest.php index c83ec6296..417ff260c 100644 --- a/tests/Composer/Test/IO/ConsoleIOTest.php +++ b/tests/Composer/Test/IO/ConsoleIOTest.php @@ -56,9 +56,10 @@ class ConsoleIOTest extends TestCase $outputMock->expects($this->once()) ->method('write') ->with( - $this->callback(function($messages){ + $this->callback(function ($messages) { $result = preg_match("[(.*)/(.*) First line]", $messages[0]) > 0; $result &= preg_match("[(.*)/(.*) Second line]", $messages[1]) > 0; + return $result; }), $this->equalTo(false) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 2c77f9bc3..0ec1f5972 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -330,8 +330,7 @@ class InstallerTest extends TestCase ); $section = null; - foreach ($tokens as $i => $token) - { + foreach ($tokens as $i => $token) { if (null === $section && empty($token)) { continue; // skip leading blank } diff --git a/tests/Composer/Test/Mock/FactoryMock.php b/tests/Composer/Test/Mock/FactoryMock.php index 52c3fbf2e..cb4c5ee25 100644 --- a/tests/Composer/Test/Mock/FactoryMock.php +++ b/tests/Composer/Test/Mock/FactoryMock.php @@ -14,7 +14,6 @@ namespace Composer\Test\Mock; use Composer\Composer; use Composer\Config; use Composer\Factory; -use Composer\Repository; use Composer\Repository\RepositoryManager; use Composer\Repository\WritableRepositoryInterface; use Composer\Installer; diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php index b03f0239c..07aaf7034 100644 --- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php @@ -169,9 +169,10 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase $self = $this; /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */ - $processExecutor = new ProcessExecutorMock(function($command, &$output = null, $cwd = null) use ($self) { + $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) { if (0 === strpos($command, 'git rev-list')) { $output = ""; + return 0; } @@ -207,9 +208,10 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase $self = $this; /* Can do away with this mock object when https://github.com/sebastianbergmann/phpunit-mock-objects/issues/81 is fixed */ - $processExecutor = new ProcessExecutorMock(function($command, &$output = null, $cwd = null) use ($self) { + $processExecutor = new ProcessExecutorMock(function ($command, &$output = null, $cwd = null) use ($self) { if (0 === strpos($command, 'git rev-list')) { $output = ""; + return 0; } diff --git a/tests/Composer/Test/Util/GitHubTest.php b/tests/Composer/Test/Util/GitHubTest.php index 4a1f3a35a..1f30c44a0 100644 --- a/tests/Composer/Test/Util/GitHubTest.php +++ b/tests/Composer/Test/Util/GitHubTest.php @@ -166,6 +166,7 @@ class GitHubTest extends \PHPUnit_Framework_TestCase return true; } } + return false; }) ) From cb336a5416595efa321c024735e6452c9c7df106 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Fri, 6 Feb 2015 13:52:44 +0100 Subject: [PATCH 36/83] Implement writeError throughout Composer --- src/Composer/Autoload/ClassMapGenerator.php | 2 +- src/Composer/Cache.php | 10 ++-- src/Composer/Command/AboutCommand.php | 2 +- src/Composer/Command/ArchiveCommand.php | 16 ++--- src/Composer/Command/ClearCacheCommand.php | 8 +-- src/Composer/Command/ConfigCommand.php | 20 +++++-- src/Composer/Command/CreateProjectCommand.php | 10 ++-- src/Composer/Command/DependsCommand.php | 4 +- src/Composer/Command/DiagnoseCommand.php | 58 +++++++++---------- src/Composer/Command/DumpAutoloadCommand.php | 4 +- src/Composer/Command/GlobalCommand.php | 2 +- src/Composer/Command/HomeCommand.php | 8 +-- src/Composer/Command/InitCommand.php | 20 +++---- src/Composer/Command/InstallCommand.php | 6 +- src/Composer/Command/LicensesCommand.php | 10 ++-- src/Composer/Command/RemoveCommand.php | 6 +- src/Composer/Command/RequireCommand.php | 12 ++-- src/Composer/Command/RunScriptCommand.php | 8 +-- src/Composer/Command/SearchCommand.php | 4 +- src/Composer/Command/SelfUpdateCommand.php | 22 +++---- src/Composer/Command/ShowCommand.php | 56 +++++++++--------- src/Composer/Command/StatusCommand.php | 12 ++-- src/Composer/Command/UpdateCommand.php | 4 +- src/Composer/Command/ValidateCommand.php | 20 +++---- src/Composer/Console/Application.php | 32 +++++----- src/Composer/Downloader/ArchiveDownloader.php | 6 +- src/Composer/Downloader/DownloadManager.php | 4 +- src/Composer/Downloader/FileDownloader.php | 20 +++---- src/Composer/Downloader/GitDownloader.php | 22 +++---- src/Composer/Downloader/HgDownloader.php | 4 +- .../Downloader/PerforceDownloader.php | 4 +- src/Composer/Downloader/SvnDownloader.php | 14 ++--- src/Composer/Downloader/VcsDownloader.php | 22 +++---- .../EventDispatcher/EventDispatcher.php | 8 +-- src/Composer/Factory.php | 10 ++-- src/Composer/IO/ConsoleIO.php | 22 +++++++ src/Composer/IO/IOInterface.php | 8 +++ src/Composer/IO/NullIO.php | 7 +++ src/Composer/Installer.php | 50 ++++++++-------- src/Composer/Installer/LibraryInstaller.php | 6 +- src/Composer/Installer/PearInstaller.php | 2 +- src/Composer/Plugin/PluginManager.php | 2 +- .../Repository/ArtifactRepository.php | 4 +- .../Repository/ComposerRepository.php | 6 +- src/Composer/Repository/PearRepository.php | 6 +- .../Repository/Vcs/GitBitbucketDriver.php | 2 +- src/Composer/Repository/Vcs/GitDriver.php | 2 +- src/Composer/Repository/Vcs/GitHubDriver.php | 8 +-- .../Repository/Vcs/HgBitbucketDriver.php | 2 +- src/Composer/Repository/Vcs/HgDriver.php | 2 +- src/Composer/Repository/VcsRepository.php | 30 +++++----- src/Composer/Util/Git.php | 2 +- src/Composer/Util/GitHub.php | 22 +++---- src/Composer/Util/ProcessExecutor.php | 2 +- src/Composer/Util/RemoteFilesystem.php | 4 +- src/Composer/Util/Svn.php | 4 +- tests/Composer/Test/ApplicationTest.php | 2 +- .../Test/Autoload/ClassMapGeneratorTest.php | 2 +- .../Downloader/PerforceDownloaderTest.php | 4 +- .../EventDispatcher/EventDispatcherTest.php | 4 +- .../functional/create-project-command.test | 2 +- ...ject-shows-full-hash-for-dev-packages.test | 2 +- tests/Composer/Test/IO/ConsoleIOTest.php | 16 +++++ tests/Composer/Test/InstallerTest.php | 15 ++--- tests/Composer/Test/Util/GitHubTest.php | 2 +- 65 files changed, 390 insertions(+), 322 deletions(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 0f289bcbd..f8f18fc28 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -92,7 +92,7 @@ class ClassMapGenerator if (!isset($map[$class])) { $map[$class] = $filePath; } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) { - $io->write( + $io->writeError( 'Warning: Ambiguous class resolution, "'.$class.'"'. ' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.' ); diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index 7341f61c2..4fae9be33 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -65,7 +65,7 @@ class Cache $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file); if ($this->enabled && file_exists($this->root . $file)) { if ($this->io->isDebug()) { - $this->io->write('Reading '.$this->root . $file.' from cache'); + $this->io->writeError('Reading '.$this->root . $file.' from cache'); } return file_get_contents($this->root . $file); @@ -80,7 +80,7 @@ class Cache $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file); if ($this->io->isDebug()) { - $this->io->write('Writing '.$this->root . $file.' into cache'); + $this->io->writeError('Writing '.$this->root . $file.' into cache'); } try { @@ -98,7 +98,7 @@ class Cache @disk_free_space($this->root . dirname($file)) ); - $this->io->write($message); + $this->io->writeError($message); return false; } @@ -120,7 +120,7 @@ class Cache $this->filesystem->ensureDirectoryExists(dirname($this->root . $file)); if ($this->io->isDebug()) { - $this->io->write('Writing '.$this->root . $file.' into cache'); + $this->io->writeError('Writing '.$this->root . $file.' into cache'); } return copy($source, $this->root . $file); @@ -139,7 +139,7 @@ class Cache touch($this->root . $file); if ($this->io->isDebug()) { - $this->io->write('Reading '.$this->root . $file.' from cache'); + $this->io->writeError('Reading '.$this->root . $file.' from cache'); } return copy($this->root . $file, $target); diff --git a/src/Composer/Command/AboutCommand.php b/src/Composer/Command/AboutCommand.php index ead7604df..5c79c65a0 100644 --- a/src/Composer/Command/AboutCommand.php +++ b/src/Composer/Command/AboutCommand.php @@ -34,7 +34,7 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { - $output->writeln(<<getIO()->write(<<Composer - Package Management for PHP Composer is a dependency manager tracking local dependencies of your projects and libraries. See http://getcomposer.org/ for more information. diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php index 913a56a42..17157a82f 100644 --- a/src/Composer/Command/ArchiveCommand.php +++ b/src/Composer/Command/ArchiveCommand.php @@ -97,7 +97,7 @@ EOT $package = $this->getComposer()->getPackage(); } - $io->write('Creating the archive.'); + $io->writeError('Creating the archive.'); $archiveManager->archive($package, $format, $dest); return 0; @@ -105,14 +105,14 @@ EOT protected function selectPackage(IOInterface $io, $packageName, $version = null) { - $io->write('Searching for the specified package.'); + $io->writeError('Searching for the specified package.'); if ($composer = $this->getComposer(false)) { $localRepo = $composer->getRepositoryManager()->getLocalRepository(); $repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories())); } else { $defaultRepos = Factory::createDefaultRepositories($this->getIO()); - $io->write('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos))); + $io->writeError('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos))); $repos = new CompositeRepository($defaultRepos); } @@ -125,14 +125,14 @@ EOT if (count($packages) > 1) { $package = reset($packages); - $io->write('Found multiple matches, selected '.$package->getPrettyString().'.'); - $io->write('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.'); - $io->write('Please use a more specific constraint to pick a different package.'); + $io->writeError('Found multiple matches, selected '.$package->getPrettyString().'.'); + $io->writeError('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.'); + $io->writeError('Please use a more specific constraint to pick a different package.'); } elseif ($packages) { $package = reset($packages); - $io->write('Found an exact match '.$package->getPrettyString().'.'); + $io->writeError('Found an exact match '.$package->getPrettyString().'.'); } else { - $io->write('Could not find a package matching '.$packageName.'.'); + $io->writeError('Could not find a package matching '.$packageName.'.'); return false; } diff --git a/src/Composer/Command/ClearCacheCommand.php b/src/Composer/Command/ClearCacheCommand.php index b1b9ecd9a..9512ba416 100644 --- a/src/Composer/Command/ClearCacheCommand.php +++ b/src/Composer/Command/ClearCacheCommand.php @@ -51,21 +51,21 @@ EOT foreach ($cachePaths as $key => $cachePath) { $cachePath = realpath($cachePath); if (!$cachePath) { - $io->write("Cache directory does not exist ($key): $cachePath"); + $io->writeError("Cache directory does not exist ($key): $cachePath"); return; } $cache = new Cache($io, $cachePath); if (!$cache->isEnabled()) { - $io->write("Cache is not enabled ($key): $cachePath"); + $io->writeError("Cache is not enabled ($key): $cachePath"); return; } - $io->write("Clearing cache ($key): $cachePath"); + $io->writeError("Clearing cache ($key): $cachePath"); $cache->gc(0, 0); } - $io->write('All caches cleared.'); + $io->writeError('All caches cleared.'); } } diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 1fd5750df..f170c9327 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -33,15 +33,25 @@ class ConfigCommand extends Command protected $config; /** - * @var Composer\Json\JsonFile + * @var JsonFile */ protected $configFile; /** - * @var Composer\Config\JsonConfigSource + * @var JsonConfigSource */ protected $configSource; + /** + * @var JsonFile + */ + protected $authConfigFile; + + /** + * @var JsonConfigSource + */ + protected $authConfigSource; + /** * {@inheritDoc} */ @@ -247,7 +257,7 @@ EOT $value = json_encode($value); } - $output->writeln($value); + $this->getIO()->write($value); return 0; } @@ -474,9 +484,9 @@ EOT } if (is_string($rawVal) && $rawVal != $value) { - $output->writeln('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')'); + $this->getIO()->write('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')'); } else { - $output->writeln('[' . $k . $key . '] ' . $value . ''); + $this->getIO()->write('[' . $k . $key . '] ' . $value . ''); } } } diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 7bf3fed15..e7186fec8 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -106,7 +106,7 @@ EOT $this->updatePreferredOptions($config, $input, $preferSource, $preferDist); if ($input->getOption('no-custom-installers')) { - $output->writeln('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); + $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); $input->setOption('no-plugins', true); } @@ -196,7 +196,7 @@ EOT } } } catch (\Exception $e) { - $io->write('An error occurred while removing the VCS metadata: '.$e->getMessage().''); + $io->writeError('An error occurred while removing the VCS metadata: '.$e->getMessage().''); } $hasVcs = false; @@ -288,10 +288,10 @@ EOT $directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts); } - $io->write('Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')'); + $io->writeError('Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')'); if ($disablePlugins) { - $io->write('Plugins have been disabled.'); + $io->writeError('Plugins have been disabled.'); } if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) { @@ -311,7 +311,7 @@ EOT $installedFromVcs = 'source' === $package->getInstallationSource(); - $io->write('Created project in ' . $directory . ''); + $io->writeError('Created project in ' . $directory . ''); chdir($directory); putenv('COMPOSER_ROOT_VERSION='.$package->getPrettyVersion()); diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php index 755b40b90..97b9d0f39 100644 --- a/src/Composer/Command/DependsCommand.php +++ b/src/Composer/Command/DependsCommand.php @@ -96,9 +96,9 @@ EOT if ($messages) { sort($messages); - $output->writeln($messages); + $this->getIO()->write($messages); } else { - $output->writeln('There is no installed package depending on "'.$needle.'".'); + $this->getIO()->writeError('There is no installed package depending on "'.$needle.'".'); } } } diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index b1fcc8dbe..d6c6ec968 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -59,8 +59,8 @@ EOT $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); - $output->write('Checking composer.json: '); - $this->outputResult($output, $this->checkComposerSchema()); + $this->getIO()->write('Checking composer.json: ', false); + $this->outputResult($this->checkComposerSchema()); } if ($composer) { @@ -72,37 +72,37 @@ EOT $this->rfs = new RemoteFilesystem($this->getIO(), $config); $this->process = new ProcessExecutor($this->getIO()); - $output->write('Checking platform settings: '); - $this->outputResult($output, $this->checkPlatform()); + $this->getIO()->write('Checking platform settings: ', false); + $this->outputResult($this->checkPlatform()); - $output->write('Checking git settings: '); - $this->outputResult($output, $this->checkGit()); + $this->getIO()->write('Checking git settings: ', false); + $this->outputResult($this->checkGit()); - $output->write('Checking http connectivity: '); - $this->outputResult($output, $this->checkHttp()); + $this->getIO()->write('Checking http connectivity: ', false); + $this->outputResult($this->checkHttp()); $opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org')); if (!empty($opts['http']['proxy'])) { - $output->write('Checking HTTP proxy: '); - $this->outputResult($output, $this->checkHttpProxy()); - $output->write('Checking HTTP proxy support for request_fulluri: '); - $this->outputResult($output, $this->checkHttpProxyFullUriRequestParam()); - $output->write('Checking HTTPS proxy support for request_fulluri: '); - $this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam()); + $this->getIO()->write('Checking HTTP proxy: ', false); + $this->outputResult($this->checkHttpProxy()); + $this->getIO()->write('Checking HTTP proxy support for request_fulluri: ', false); + $this->outputResult($this->checkHttpProxyFullUriRequestParam()); + $this->getIO()->write('Checking HTTPS proxy support for request_fulluri: ', false); + $this->outputResult($this->checkHttpsProxyFullUriRequestParam()); } if ($oauth = $config->get('github-oauth')) { foreach ($oauth as $domain => $token) { - $output->write('Checking '.$domain.' oauth access: '); - $this->outputResult($output, $this->checkGithubOauth($domain, $token)); + $this->getIO()->write('Checking '.$domain.' oauth access: ', false); + $this->outputResult($this->checkGithubOauth($domain, $token)); } } else { - $output->write('Checking github.com rate limit: '); + $this->getIO()->write('Checking github.com rate limit: ', false); $rate = $this->getGithubRateLimit('github.com'); if (10 > $rate['remaining']) { - $output->writeln('WARNING'); - $output->writeln(sprintf( + $this->getIO()->write('WARNING'); + $this->getIO()->write(sprintf( 'Github has a rate limit on their API. ' . 'You currently have %u ' . 'out of %u requests left.' . PHP_EOL @@ -112,15 +112,15 @@ EOT $rate['limit'] )); } else { - $output->writeln('OK'); + $this->getIO()->write('OK'); } } - $output->write('Checking disk free space: '); - $this->outputResult($output, $this->checkDiskSpace($config)); + $this->getIO()->write('Checking disk free space: ', false); + $this->outputResult($this->checkDiskSpace($config)); - $output->write('Checking composer version: '); - $this->outputResult($output, $this->checkVersion()); + $this->getIO()->write('Checking composer version: ', false); + $this->outputResult($this->checkVersion()); return $this->failures; } @@ -308,17 +308,17 @@ EOT return true; } - private function outputResult(OutputInterface $output, $result) + private function outputResult($result) { if (true === $result) { - $output->writeln('OK'); + $this->getIO()->write('OK'); } else { $this->failures++; - $output->writeln('FAIL'); + $this->getIO()->write('FAIL'); if ($result instanceof \Exception) { - $output->writeln('['.get_class($result).'] '.$result->getMessage()); + $this->getIO()->write('['.get_class($result).'] '.$result->getMessage()); } elseif ($result) { - $output->writeln(trim($result)); + $this->getIO()->write(trim($result)); } } } diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php index adcc7adfd..f560953b8 100644 --- a/src/Composer/Command/DumpAutoloadCommand.php +++ b/src/Composer/Command/DumpAutoloadCommand.php @@ -55,9 +55,9 @@ EOT $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative'); if ($optimize) { - $output->writeln('Generating optimized autoload files'); + $this->getIO()->writeError('Generating optimized autoload files'); } else { - $output->writeln('Generating autoload files'); + $this->getIO()->writeError('Generating autoload files'); } $generator = $composer->getAutoloadGenerator(); diff --git a/src/Composer/Command/GlobalCommand.php b/src/Composer/Command/GlobalCommand.php index 15f1fff08..502ce5e8a 100644 --- a/src/Composer/Command/GlobalCommand.php +++ b/src/Composer/Command/GlobalCommand.php @@ -72,7 +72,7 @@ EOT // change to global dir $config = Factory::createConfig(); chdir($config->get('home')); - $output->writeln('Changed current directory to '.$config->get('home').''); + $this->getIO()->writeError('Changed current directory to '.$config->get('home').''); // create new input without "global" command prefix $input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1)); diff --git a/src/Composer/Command/HomeCommand.php b/src/Composer/Command/HomeCommand.php index 5ea193d5c..51a135c68 100644 --- a/src/Composer/Command/HomeCommand.php +++ b/src/Composer/Command/HomeCommand.php @@ -71,7 +71,7 @@ EOT if (!$package instanceof CompletePackageInterface) { $return = 1; - $output->writeln('Package '.$packageName.' not found'); + $this->getIO()->writeError('Package '.$packageName.' not found'); continue; } @@ -84,13 +84,13 @@ EOT if (!filter_var($url, FILTER_VALIDATE_URL)) { $return = 1; - $output->writeln(''.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.''); + $this->getIO()->writeError(''.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.''); continue; } if ($input->getOption('show')) { - $output->writeln(sprintf('%s', $url)); + $this->getIO()->write(sprintf('%s', $url)); } else { $this->openBrowser($url); } @@ -145,7 +145,7 @@ EOT } elseif (0 === $osx) { passthru('open ' . $url); } else { - $this->getIO()->write('no suitable browser opening command found, open yourself: ' . $url); + $this->getIO()->writeError('no suitable browser opening command found, open yourself: ' . $url); } } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 38dc2c4a5..7f146c2e5 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -117,13 +117,13 @@ EOT $json = $file->encode($options); if ($input->isInteractive()) { - $output->writeln(array( + $this->getIO()->writeError(array( '', $json, '' )); if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) { - $output->writeln('Command aborted'); + $this->getIO()->writeError('Command aborted'); return 1; } @@ -154,14 +154,14 @@ EOT $dialog = $this->getHelperSet()->get('dialog'); $formatter = $this->getHelperSet()->get('formatter'); - $output->writeln(array( + $this->getIO()->writeError(array( '', $formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true), '' )); // namespace - $output->writeln(array( + $this->getIO()->writeError(array( '', 'This command will guide you through creating your composer.json config.', '', @@ -266,7 +266,7 @@ EOT ); $input->setOption('license', $license); - $output->writeln(array( + $this->getIO()->writeError(array( '', 'Define your dependencies.', '' @@ -316,7 +316,7 @@ EOT $version = $this->findBestVersionForPackage($input, $requirement['name']); $requirement['version'] = $version; - $output->writeln(sprintf( + $this->getIO()->writeError(sprintf( 'Using version %s for %s', $requirement['version'], $requirement['name'] @@ -345,14 +345,14 @@ EOT // no match, prompt which to pick if (!$exactMatch) { - $output->writeln(array( + $this->getIO()->writeError(array( '', sprintf('Found %s packages matching %s', count($matches), $package), '' )); - $output->writeln($choices); - $output->writeln(''); + $this->getIO()->writeError($choices); + $this->getIO()->writeError(''); $validator = function ($selection) use ($matches) { if ('' === $selection) { @@ -392,7 +392,7 @@ EOT if (false === $constraint) { $constraint = $this->findBestVersionForPackage($input, $package); - $output->writeln(sprintf( + $this->getIO()->writeError(sprintf( 'Using version %s for %s', $constraint, $package diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index 115e1d6af..e548b8d69 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -65,18 +65,18 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { if ($args = $input->getArgument('packages')) { - $output->writeln('Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.'); + $this->getIO()->writeError('Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.'); return 1; } if ($input->getOption('no-custom-installers')) { - $output->writeln('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); + $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); $input->setOption('no-plugins', true); } if ($input->getOption('dev')) { - $output->writeln('You are using the deprecated option "dev". Dev packages are installed by default now.'); + $this->getIO()->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.'); } $composer = $this->getComposer(true, $input->getOption('no-plugins')); diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 757de6d87..07b7b548b 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -68,10 +68,10 @@ EOT switch ($format = $input->getOption('format')) { case 'text': - $output->writeln('Name: '.$root->getPrettyName().''); - $output->writeln('Version: '.$versionParser->formatVersion($root).''); - $output->writeln('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').''); - $output->writeln('Dependencies:'); + $this->getIO()->write('Name: '.$root->getPrettyName().''); + $this->getIO()->write('Version: '.$versionParser->formatVersion($root).''); + $this->getIO()->write('Licenses: '.(implode(', ', $root->getLicense()) ?: 'none').''); + $this->getIO()->write('Dependencies:'); $table = new Table($output); $table->setStyle('borderless'); @@ -94,7 +94,7 @@ EOT ); } - $output->writeln(JsonFile::encode(array( + $this->getIO()->write(JsonFile::encode(array( 'name' => $root->getPrettyName(), 'version' => $versionParser->formatVersion($root), 'license' => $root->getLicense(), diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index c292a2812..8821bd991 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -73,7 +73,7 @@ EOT if (isset($composer[$type][$package])) { $json->removeLink($type, $package); } elseif (isset($composer[$altType][$package])) { - $output->writeln(''.$package.' could not be found in '.$type.' but it is present in '.$altType.''); + $this->getIO()->writeError(''.$package.' could not be found in '.$type.' but it is present in '.$altType.''); $dialog = $this->getHelperSet()->get('dialog'); if ($this->getIO()->isInteractive()) { if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) { @@ -81,7 +81,7 @@ EOT } } } else { - $output->writeln(''.$package.' is not required in your composer.json and has not been removed'); + $this->getIO()->writeError(''.$package.' is not required in your composer.json and has not been removed'); } } @@ -111,7 +111,7 @@ EOT $status = $install->run(); if ($status !== 0) { - $output->writeln("\n".'Removal failed, reverting '.$file.' to its original content.'); + $this->getIO()->writeError("\n".'Removal failed, reverting '.$file.' to its original content.'); file_put_contents($jsonFile->getPath(), $composerBackup); } diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index ea972aaf0..4391f1d05 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -67,17 +67,17 @@ EOT $newlyCreated = !file_exists($file); if (!file_exists($file) && !file_put_contents($file, "{\n}\n")) { - $output->writeln(''.$file.' could not be created.'); + $this->getIO()->writeError(''.$file.' could not be created.'); return 1; } if (!is_readable($file)) { - $output->writeln(''.$file.' is not readable.'); + $this->getIO()->writeError(''.$file.' is not readable.'); return 1; } if (!is_writable($file)) { - $output->writeln(''.$file.' is not writable.'); + $this->getIO()->writeError(''.$file.' is not writable.'); return 1; } @@ -122,7 +122,7 @@ EOT $json->write($composerDefinition); } - $output->writeln(''.$file.' has been '.($newlyCreated ? 'created' : 'updated').''); + $this->getIO()->writeError(''.$file.' has been '.($newlyCreated ? 'created' : 'updated').''); if ($input->getOption('no-update')) { return 0; @@ -154,10 +154,10 @@ EOT $status = $install->run(); if ($status !== 0) { if ($newlyCreated) { - $output->writeln("\n".'Installation failed, deleting '.$file.'.'); + $this->getIO()->writeError("\n".'Installation failed, deleting '.$file.'.'); unlink($json->getPath()); } else { - $output->writeln("\n".'Installation failed, reverting '.$file.' to its original content.'); + $this->getIO()->writeError("\n".'Installation failed, reverting '.$file.' to its original content.'); file_put_contents($json->getPath(), $composerBackup); } } diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index 7e9fe6845..979f86a02 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -66,7 +66,7 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('list')) { - return $this->listScripts($input, $output); + return $this->listScripts(); } elseif (!$input->getArgument('script')) { throw new \RunTimeException('Missing required argument "script"'); } @@ -95,7 +95,7 @@ EOT return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args); } - protected function listScripts(InputInterface $input, OutputInterface $output) + protected function listScripts() { $scripts = $this->getComposer()->getPackage()->getScripts(); @@ -103,9 +103,9 @@ EOT return 0; } - $output->writeln('scripts:'); + $this->getIO()->writeError('scripts:'); foreach ($scripts as $name => $script) { - $output->writeln(' ' . $name); + $this->getIO()->write(' ' . $name); } return 0; diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php index b9aaa8d74..54990f30d 100644 --- a/src/Composer/Command/SearchCommand.php +++ b/src/Composer/Command/SearchCommand.php @@ -62,7 +62,7 @@ EOT $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories())); } else { $defaultRepos = Factory::createDefaultRepositories($this->getIO()); - $output->writeln('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos))); + $this->getIO()->writeError('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos))); $installedRepo = $platformRepo; $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos)); } @@ -78,7 +78,7 @@ EOT $results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags); foreach ($results as $result) { - $output->writeln($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); + $this->getIO()->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); } } } diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index eb0de083e..e4e96e8f4 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -84,13 +84,13 @@ EOT $updateVersion = $input->getArgument('version') ?: $latestVersion; if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) { - $output->writeln('You can not update to a specific SHA-1 as those phars are not available for download'); + $this->getIO()->writeError('You can not update to a specific SHA-1 as those phars are not available for download'); return 1; } if (Composer::VERSION === $updateVersion) { - $output->writeln('You are already using composer version '.$updateVersion.'.'); + $this->getIO()->writeError('You are already using composer version '.$updateVersion.'.'); return 0; } @@ -104,11 +104,11 @@ EOT self::OLD_INSTALL_EXT ); - $output->writeln(sprintf("Updating to version %s.", $updateVersion)); + $this->getIO()->writeError(sprintf("Updating to version %s.", $updateVersion)); $remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar"); $remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress')); if (!file_exists($tempFilename)) { - $output->writeln('The download of the new composer version failed for an unexpected reason'); + $this->getIO()->writeError('The download of the new composer version failed for an unexpected reason'); return 1; } @@ -120,22 +120,22 @@ EOT $fs = new Filesystem; foreach ($finder as $file) { $file = (string) $file; - $output->writeln('Removing: '.$file.''); + $this->getIO()->writeError('Removing: '.$file.''); $fs->remove($file); } } if ($err = $this->setLocalPhar($localFilename, $tempFilename, $backupFile)) { - $output->writeln('The file is corrupted ('.$err->getMessage().').'); - $output->writeln('Please re-run the self-update command to try again.'); + $this->getIO()->writeError('The file is corrupted ('.$err->getMessage().').'); + $this->getIO()->writeError('Please re-run the self-update command to try again.'); return 1; } if (file_exists($backupFile)) { - $output->writeln('Use composer self-update --rollback to return to version '.Composer::VERSION); + $this->getIO()->writeError('Use composer self-update --rollback to return to version '.Composer::VERSION); } else { - $output->writeln('A backup of the current version could not be written to '.$backupFile.', no rollback possible'); + $this->getIO()->writeError('A backup of the current version could not be written to '.$backupFile.', no rollback possible'); } } @@ -160,9 +160,9 @@ EOT } $oldFile = $rollbackDir . "/{$rollbackVersion}" . self::OLD_INSTALL_EXT; - $output->writeln(sprintf("Rolling back to version %s.", $rollbackVersion)); + $this->getIO()->writeError(sprintf("Rolling back to version %s.", $rollbackVersion)); if ($err = $this->setLocalPhar($localFilename, $oldFile)) { - $output->writeln('The backup file was corrupted ('.$err->getMessage().') and has been removed.'); + $this->getIO()->writeError('The backup file was corrupted ('.$err->getMessage().') and has been removed.'); return 1; } diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 907e99f90..6f2a1dab6 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -84,7 +84,7 @@ EOT } else { $defaultRepos = Factory::createDefaultRepositories($this->getIO()); $repos = new CompositeRepository($defaultRepos); - $output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos))); + $this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos))); } } elseif ($composer) { $localRepo = $composer->getRepositoryManager()->getLocalRepository(); @@ -92,7 +92,7 @@ EOT $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories())); } else { $defaultRepos = Factory::createDefaultRepositories($this->getIO()); - $output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos))); + $this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos))); $installedRepo = $platformRepo; $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos)); } @@ -119,9 +119,9 @@ EOT $this->printLinks($input, $output, $package, 'requires'); $this->printLinks($input, $output, $package, 'devRequires', 'requires (dev)'); if ($package->getSuggests()) { - $output->writeln("\nsuggests"); + $this->getIO()->write("\nsuggests"); foreach ($package->getSuggests() as $suggested => $reason) { - $output->writeln($suggested . ' ' . $reason . ''); + $this->getIO()->write($suggested . ' ' . $reason . ''); } } $this->printLinks($input, $output, $package, 'provides'); @@ -172,7 +172,7 @@ EOT foreach (array('platform:' => true, 'available:' => false, 'installed:' => true) as $type => $showVersion) { if (isset($packages[$type])) { if ($tree) { - $output->writeln($type); + $this->getIO()->write($type); } ksort($packages[$type]); @@ -222,10 +222,10 @@ EOT } else { $output->write($indent . $package); } - $output->writeln(''); + $this->getIO()->write(''); } if ($tree) { - $output->writeln(''); + $this->getIO()->write(''); } } } @@ -285,53 +285,53 @@ EOT */ protected function printMeta(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos) { - $output->writeln('name : ' . $package->getPrettyName()); - $output->writeln('descrip. : ' . $package->getDescription()); - $output->writeln('keywords : ' . join(', ', $package->getKeywords() ?: array())); + $this->getIO()->write('name : ' . $package->getPrettyName()); + $this->getIO()->write('descrip. : ' . $package->getDescription()); + $this->getIO()->write('keywords : ' . join(', ', $package->getKeywords() ?: array())); $this->printVersions($input, $output, $package, $versions, $installedRepo, $repos); - $output->writeln('type : ' . $package->getType()); - $output->writeln('license : ' . implode(', ', $package->getLicense())); - $output->writeln('source : ' . sprintf('[%s] %s %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference())); - $output->writeln('dist : ' . sprintf('[%s] %s %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference())); - $output->writeln('names : ' . implode(', ', $package->getNames())); + $this->getIO()->write('type : ' . $package->getType()); + $this->getIO()->write('license : ' . implode(', ', $package->getLicense())); + $this->getIO()->write('source : ' . sprintf('[%s] %s %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference())); + $this->getIO()->write('dist : ' . sprintf('[%s] %s %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference())); + $this->getIO()->write('names : ' . implode(', ', $package->getNames())); if ($package->isAbandoned()) { $replacement = ($package->getReplacementPackage() !== null) ? ' The author suggests using the ' . $package->getReplacementPackage(). ' package instead.' : null; - $output->writeln( + $this->getIO()->writeError( sprintf('Attention: This package is abandoned and no longer maintained.%s', $replacement) ); } if ($package->getSupport()) { - $output->writeln("\nsupport"); + $this->getIO()->write("\nsupport"); foreach ($package->getSupport() as $type => $value) { - $output->writeln('' . $type . ' : '.$value); + $this->getIO()->write('' . $type . ' : '.$value); } } if ($package->getAutoload()) { - $output->writeln("\nautoload"); + $this->getIO()->write("\nautoload"); foreach ($package->getAutoload() as $type => $autoloads) { - $output->writeln('' . $type . ''); + $this->getIO()->write('' . $type . ''); if ($type === 'psr-0') { foreach ($autoloads as $name => $path) { - $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); + $this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); } } elseif ($type === 'psr-4') { foreach ($autoloads as $name => $path) { - $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); + $this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); } } elseif ($type === 'classmap') { - $output->writeln(implode(', ', $autoloads)); + $this->getIO()->write(implode(', ', $autoloads)); } } if ($package->getIncludePaths()) { - $output->writeln('include-path'); - $output->writeln(implode(', ', $package->getIncludePaths())); + $this->getIO()->write('include-path'); + $this->getIO()->write(implode(', ', $package->getIncludePaths())); } } } @@ -355,7 +355,7 @@ EOT $versions = implode(', ', $versions); - $output->writeln('versions : ' . $versions); + $this->getIO()->write('versions : ' . $versions); } /** @@ -371,10 +371,10 @@ EOT { $title = $title ?: $linkType; if ($links = $package->{'get'.ucfirst($linkType)}()) { - $output->writeln("\n" . $title . ""); + $this->getIO()->write("\n" . $title . ""); foreach ($links as $link) { - $output->writeln($link->getTarget() . ' ' . $link->getPrettyConstraint() . ''); + $this->getIO()->write($link->getTarget() . ' ' . $link->getPrettyConstraint() . ''); } } } diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index e458c8fb9..220327cb6 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -76,9 +76,9 @@ EOT // output errors/warnings if (!$errors) { - $output->writeln('No local changes'); + $this->getIO()->writeError('No local changes'); } else { - $output->writeln('You have changes in the following dependencies:'); + $this->getIO()->writeError('You have changes in the following dependencies:'); } foreach ($errors as $path => $changes) { @@ -86,15 +86,15 @@ EOT $indentedChanges = implode("\n", array_map(function ($line) { return ' ' . ltrim($line); }, explode("\n", $changes))); - $output->writeln(''.$path.':'); - $output->writeln($indentedChanges); + $this->getIO()->write(''.$path.':'); + $this->getIO()->write($indentedChanges); } else { - $output->writeln($path); + $this->getIO()->write($path); } } if ($errors && !$input->getOption('verbose')) { - $output->writeln('Use --verbose (-v) to see modified files'); + $this->getIO()->writeError('Use --verbose (-v) to see modified files'); } // Dispatch post-status-command diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 460075f0f..579236143 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -75,12 +75,12 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('no-custom-installers')) { - $output->writeln('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); + $this->getIO()->writeError('You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.'); $input->setOption('no-plugins', true); } if ($input->getOption('dev')) { - $output->writeln('You are using the deprecated option "dev". Dev packages are installed by default now.'); + $this->getIO()->writeError('You are using the deprecated option "dev". Dev packages are installed by default now.'); } $composer = $this->getComposer(true, $input->getOption('no-plugins')); diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php index e7e0860e1..08aaef209 100644 --- a/src/Composer/Command/ValidateCommand.php +++ b/src/Composer/Command/ValidateCommand.php @@ -57,12 +57,12 @@ EOT $file = $input->getArgument('file'); if (!file_exists($file)) { - $output->writeln('' . $file . ' not found.'); + $this->getIO()->writeError('' . $file . ' not found.'); return 1; } if (!is_readable($file)) { - $output->writeln('' . $file . ' is not readable.'); + $this->getIO()->writeError('' . $file . ' is not readable.'); return 1; } @@ -73,16 +73,16 @@ EOT // output errors/warnings if (!$errors && !$publishErrors && !$warnings) { - $output->writeln('' . $file . ' is valid'); + $this->getIO()->write('' . $file . ' is valid'); } elseif (!$errors && !$publishErrors) { - $output->writeln('' . $file . ' is valid, but with a few warnings'); - $output->writeln('See http://getcomposer.org/doc/04-schema.md for details on the schema'); + $this->getIO()->writeError('' . $file . ' is valid, but with a few warnings'); + $this->getIO()->writeError('See http://getcomposer.org/doc/04-schema.md for details on the schema'); } elseif (!$errors) { - $output->writeln('' . $file . ' is valid for simple usage with composer but has'); - $output->writeln('strict errors that make it unable to be published as a package:'); - $output->writeln('See http://getcomposer.org/doc/04-schema.md for details on the schema'); + $this->getIO()->writeError('' . $file . ' is valid for simple usage with composer but has'); + $this->getIO()->writeError('strict errors that make it unable to be published as a package:'); + $this->getIO()->writeError('See http://getcomposer.org/doc/04-schema.md for details on the schema'); } else { - $output->writeln('' . $file . ' is invalid, the following errors/warnings were found:'); + $this->getIO()->writeError('' . $file . ' is invalid, the following errors/warnings were found:'); } $messages = array( @@ -92,7 +92,7 @@ EOT foreach ($messages as $style => $msgs) { foreach ($msgs as $msg) { - $output->writeln('<' . $style . '>' . $msg . ''); + $this->getIO()->writeError('<' . $style . '>' . $msg . ''); } } diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 1c8246f88..f318832bc 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -15,6 +15,7 @@ namespace Composer\Console; use Symfony\Component\Console\Application as BaseApplication; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Formatter\OutputFormatter; @@ -91,7 +92,7 @@ class Application extends BaseApplication $this->io = new ConsoleIO($input, $output, $this->getHelperSet()); if (version_compare(PHP_VERSION, '5.3.2', '<')) { - $output->writeln('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.'); + $this->getIO()->writeError('Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.'); } if (defined('COMPOSER_DEV_WARNING_TIME')) { @@ -104,7 +105,7 @@ class Application extends BaseApplication } if ($commandName !== 'self-update' && $commandName !== 'selfupdate') { if (time() > COMPOSER_DEV_WARNING_TIME) { - $output->writeln(sprintf('Warning: This development build of composer is over 30 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF'])); + $this->getIO()->writeError(sprintf('Warning: This development build of composer is over 30 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF'])); } } } @@ -117,8 +118,8 @@ class Application extends BaseApplication if ($newWorkDir = $this->getNewWorkingDir($input)) { $oldWorkingDir = getcwd(); chdir($newWorkDir); - if ($output->getVerbosity() >= 4) { - $output->writeln('Changed CWD to ' . getcwd()); + if ($this->getIO()->isDebug() >= 4) { + $this->getIO()->writeError('Changed CWD to ' . getcwd()); } } @@ -129,7 +130,7 @@ class Application extends BaseApplication foreach ($composer['scripts'] as $script => $dummy) { if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) { if ($this->has($script)) { - $output->writeln('A script named '.$script.' would override a native Composer function and has been skipped'); + $this->getIO()->writeError('A script named '.$script.' would override a native Composer function and has been skipped'); } else { $this->add(new Command\ScriptAliasCommand($script)); } @@ -150,7 +151,7 @@ class Application extends BaseApplication } if (isset($startTime)) { - $output->writeln('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s'); + $this->getIO->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s'); } return $result; @@ -186,23 +187,27 @@ class Application extends BaseApplication || (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree) || (($df = @disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree) ) { - $output->writeln('The disk hosting '.$dir.' is full, this may be the cause of the following exception'); + $this->getIO()->writeError('The disk hosting '.$dir.' is full, this may be the cause of the following exception'); } } } catch (\Exception $e) { } if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) { - $output->writeln('The following exception may be caused by a stale entry in your cmd.exe AutoRun'); - $output->writeln('Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details'); + $this->getIO()->writeError('The following exception may be caused by a stale entry in your cmd.exe AutoRun'); + $this->getIO()->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details'); } if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) { - $output->writeln('The following exception is caused by a lack of memory and not having swap configured'); - $output->writeln('Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details'); + $this->getIO()->writeError('The following exception is caused by a lack of memory and not having swap configured'); + $this->getIO()->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details'); } - return parent::renderException($exception, $output); + if ($output instanceof ConsoleOutputInterface) { + parent::renderException($exception, $output->getErrorOutput()); + } else { + parent::renderException($exception, $output); + } } /** @@ -218,7 +223,7 @@ class Application extends BaseApplication $this->composer = Factory::create($this->io, null, $disablePlugins); } catch (\InvalidArgumentException $e) { if ($required) { - $this->io->write($e->getMessage()); + $this->io->writeError($e->getMessage()); exit(1); } } catch (JsonValidationException $e) { @@ -323,7 +328,6 @@ class Application extends BaseApplication protected function getDefaultHelperSet() { $helperSet = parent::getDefaultHelperSet(); - $helperSet->set(new DialogHelper()); return $helperSet; diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 204c09154..35dfe308a 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -35,7 +35,7 @@ abstract class ArchiveDownloader extends FileDownloader $fileName = parent::download($package, $path); if ($this->io->isVerbose()) { - $this->io->write(' Extracting archive'); + $this->io->writeError(' Extracting archive'); } try { @@ -77,7 +77,7 @@ abstract class ArchiveDownloader extends FileDownloader // retry downloading if we have an invalid zip file if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) { - $this->io->write(' Invalid zip file, retrying...'); + $this->io->writeError(' Invalid zip file, retrying...'); usleep(500000); continue; } @@ -88,7 +88,7 @@ abstract class ArchiveDownloader extends FileDownloader break; } - $this->io->write(''); + $this->io->writeError(''); } /** diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index 4bbbae5a9..5c0980725 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -192,7 +192,7 @@ class DownloadManager foreach ($sources as $i => $source) { if (isset($e)) { - $this->io->write(' Now trying to download from ' . $source . ''); + $this->io->writeError(' Now trying to download from ' . $source . ''); } $package->setInstallationSource($source); try { @@ -206,7 +206,7 @@ class DownloadManager throw $e; } - $this->io->write( + $this->io->writeError( ' Failed to download '. $package->getPrettyName(). ' from ' . $source . ': '. diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 96bd57c06..04f8fc4b5 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -81,7 +81,7 @@ class FileDownloader implements DownloaderInterface throw new \InvalidArgumentException('The given package is missing url information'); } - $this->io->write(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); + $this->io->writeError(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); $urls = $package->getDistUrls(); while ($url = array_shift($urls)) { @@ -89,11 +89,11 @@ class FileDownloader implements DownloaderInterface return $this->doDownload($package, $path, $url); } catch (\Exception $e) { if ($this->io->isDebug()) { - $this->io->write(''); - $this->io->write('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage()); + $this->io->writeError(''); + $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage()); } elseif (count($urls)) { - $this->io->write(''); - $this->io->write(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')'); + $this->io->writeError(''); + $this->io->writeError(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')'); } if (!count($urls)) { @@ -102,7 +102,7 @@ class FileDownloader implements DownloaderInterface } } - $this->io->write(''); + $this->io->writeError(''); } protected function doDownload(PackageInterface $package, $path, $url) @@ -127,7 +127,7 @@ class FileDownloader implements DownloaderInterface // download if we don't have it in cache or the cache is invalidated if (!$this->cache || ($checksum && $checksum !== $this->cache->sha1($cacheKey)) || !$this->cache->copyTo($cacheKey, $fileName)) { if (!$this->outputProgress) { - $this->io->write(' Downloading'); + $this->io->writeError(' Downloading'); } // try to download 3 times then fail hard @@ -142,7 +142,7 @@ class FileDownloader implements DownloaderInterface throw $e; } if ($this->io->isVerbose()) { - $this->io->write(' Download failed, retrying...'); + $this->io->writeError(' Download failed, retrying...'); } usleep(500000); } @@ -152,7 +152,7 @@ class FileDownloader implements DownloaderInterface $this->cache->copyFrom($cacheKey, $fileName); } } else { - $this->io->write(' Loading from cache'); + $this->io->writeError(' Loading from cache'); } if (!file_exists($fileName)) { @@ -205,7 +205,7 @@ class FileDownloader implements DownloaderInterface */ public function remove(PackageInterface $package, $path) { - $this->io->write(" - Removing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); + $this->io->writeError(" - Removing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); if (!$this->filesystem->removeDirectory($path)) { throw new \RuntimeException('Could not completely delete '.$path.', aborting.'); } diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index bdebaf4cf..dd8086b84 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -45,7 +45,7 @@ class GitDownloader extends VcsDownloader $ref = $package->getSourceReference(); $flag = defined('PHP_WINDOWS_VERSION_MAJOR') ? '/D ' : ''; $command = 'git clone --no-checkout %s %s && cd '.$flag.'%2$s && git remote add composer %1$s && git fetch composer'; - $this->io->write(" Cloning ".$ref); + $this->io->writeError(" Cloning ".$ref); $commandCallable = function ($url) use ($ref, $path, $command) { return sprintf($command, ProcessExecutor::escape($url), ProcessExecutor::escape($path), ProcessExecutor::escape($ref)); @@ -78,7 +78,7 @@ class GitDownloader extends VcsDownloader } $ref = $target->getSourceReference(); - $this->io->write(" Checking out ".$ref); + $this->io->writeError(" Checking out ".$ref); $command = 'git remote set-url composer %s && git fetch composer && git fetch --tags composer'; $commandCallable = function ($url) use ($command) { @@ -143,10 +143,10 @@ class GitDownloader extends VcsDownloader $changes = array_map(function ($elem) { return ' '.$elem; }, preg_split('{\s*\r?\n\s*}', $changes)); - $this->io->write(' The package has modified files:'); - $this->io->write(array_slice($changes, 0, 10)); + $this->io->writeError(' The package has modified files:'); + $this->io->writeError(array_slice($changes, 0, 10)); if (count($changes) > 10) { - $this->io->write(' '.count($changes) - 10 . ' more files modified, choose "v" to view the full list'); + $this->io->writeError(' '.count($changes) - 10 . ' more files modified, choose "v" to view the full list'); } while (true) { @@ -167,21 +167,21 @@ class GitDownloader extends VcsDownloader throw new \RuntimeException('Update aborted'); case 'v': - $this->io->write($changes); + $this->io->writeError($changes); break; case '?': default: help: - $this->io->write(array( + $this->io->writeError(array( ' y - discard changes and apply the '.($update ? 'update' : 'uninstall'), ' n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up', ' v - view modified files', )); if ($update) { - $this->io->write(' s - stash changes and try to reapply them after the update'); + $this->io->writeError(' s - stash changes and try to reapply them after the update'); } - $this->io->write(' ? - print help'); + $this->io->writeError(' ? - print help'); break; } } @@ -195,7 +195,7 @@ class GitDownloader extends VcsDownloader $path = $this->normalizePath($path); if ($this->hasStashedChanges) { $this->hasStashedChanges = false; - $this->io->write(' Re-applying stashed changes'); + $this->io->writeError(' Re-applying stashed changes'); if (0 !== $this->process->execute('git stash pop', $output, $path)) { throw new \RuntimeException("Failed to apply stashed changes:\n\n".$this->process->getErrorOutput()); } @@ -261,7 +261,7 @@ class GitDownloader extends VcsDownloader // reference was not found (prints "fatal: reference is not a tree: $ref") if (false !== strpos($this->process->getErrorOutput(), $reference)) { - $this->io->write(' '.$reference.' is gone (history was rewritten?)'); + $this->io->writeError(' '.$reference.' is gone (history was rewritten?)'); } throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index 3d5cc6209..117cc5a17 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -27,7 +27,7 @@ class HgDownloader extends VcsDownloader { $url = ProcessExecutor::escape($url); $ref = ProcessExecutor::escape($package->getSourceReference()); - $this->io->write(" Cloning ".$package->getSourceReference()); + $this->io->writeError(" Cloning ".$package->getSourceReference()); $command = sprintf('hg clone %s %s', $url, ProcessExecutor::escape($path)); if (0 !== $this->process->execute($command, $ignoredOutput)) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); @@ -45,7 +45,7 @@ class HgDownloader extends VcsDownloader { $url = ProcessExecutor::escape($url); $ref = ProcessExecutor::escape($target->getSourceReference()); - $this->io->write(" Updating to ".$target->getSourceReference()); + $this->io->writeError(" Updating to ".$target->getSourceReference()); if (!is_dir($path.'/.hg')) { throw new \RuntimeException('The .hg directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information'); diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php index 683ea9f34..ae2769999 100644 --- a/src/Composer/Downloader/PerforceDownloader.php +++ b/src/Composer/Downloader/PerforceDownloader.php @@ -31,7 +31,7 @@ class PerforceDownloader extends VcsDownloader $ref = $package->getSourceReference(); $label = $this->getLabelFromSourceReference($ref); - $this->io->write(' Cloning ' . $ref); + $this->io->writeError(' Cloning ' . $ref); $this->initPerforce($package, $path, $url); $this->perforce->setStream($ref); $this->perforce->p4Login($this->io); @@ -85,7 +85,7 @@ class PerforceDownloader extends VcsDownloader */ public function getLocalChanges(PackageInterface $package, $path) { - $this->io->write('Perforce driver does not check for local changes before overriding', true); + $this->io->writeError('Perforce driver does not check for local changes before overriding', true); return; } diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 689781f6c..975780eb8 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -29,7 +29,7 @@ class SvnDownloader extends VcsDownloader SvnUtil::cleanEnv(); $ref = $package->getSourceReference(); - $this->io->write(" Checking out ".$package->getSourceReference()); + $this->io->writeError(" Checking out ".$package->getSourceReference()); $this->execute($url, "svn co", sprintf("%s/%s", $url, $ref), null, $path); } @@ -52,7 +52,7 @@ class SvnDownloader extends VcsDownloader } } - $this->io->write(" Checking out " . $ref); + $this->io->writeError(" Checking out " . $ref); $this->execute($url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path); } @@ -114,10 +114,10 @@ class SvnDownloader extends VcsDownloader $changes = array_map(function ($elem) { return ' '.$elem; }, preg_split('{\s*\r?\n\s*}', $changes)); - $this->io->write(' The package has modified files:'); - $this->io->write(array_slice($changes, 0, 10)); + $this->io->writeError(' The package has modified files:'); + $this->io->writeError(array_slice($changes, 0, 10)); if (count($changes) > 10) { - $this->io->write(' '.count($changes) - 10 . ' more files modified, choose "v" to view the full list'); + $this->io->writeError(' '.count($changes) - 10 . ' more files modified, choose "v" to view the full list'); } while (true) { @@ -130,12 +130,12 @@ class SvnDownloader extends VcsDownloader throw new \RuntimeException('Update aborted'); case 'v': - $this->io->write($changes); + $this->io->writeError($changes); break; case '?': default: - $this->io->write(array( + $this->io->writeError(array( ' y - discard changes and apply the '.($update ? 'update' : 'uninstall'), ' n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up', ' v - view modified files', diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php index e653794ca..254f6143d 100644 --- a/src/Composer/Downloader/VcsDownloader.php +++ b/src/Composer/Downloader/VcsDownloader.php @@ -54,7 +54,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information'); } - $this->io->write(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); + $this->io->writeError(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); $this->filesystem->emptyDirectory($path); $urls = $package->getSourceUrls(); @@ -67,9 +67,9 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa break; } catch (\Exception $e) { if ($this->io->isDebug()) { - $this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage()); + $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage()); } elseif (count($urls)) { - $this->io->write(' Failed, trying the next URL'); + $this->io->writeError(' Failed, trying the next URL'); } if (!count($urls)) { throw $e; @@ -77,7 +77,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa } } - $this->io->write(''); + $this->io->writeError(''); } /** @@ -104,7 +104,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa $to = VersionParser::formatVersion($target); } - $this->io->write(" - Updating " . $name . " (" . $from . " => " . $to . ")"); + $this->io->writeError(" - Updating " . $name . " (" . $from . " => " . $to . ")"); $this->cleanChanges($initial, $path, true); $urls = $target->getSourceUrls(); @@ -117,9 +117,9 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa break; } catch (\Exception $e) { if ($this->io->isDebug()) { - $this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage()); + $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage()); } elseif (count($urls)) { - $this->io->write(' Failed, trying the next URL'); + $this->io->writeError(' Failed, trying the next URL'); } else { // in case of failed update, try to reapply the changes before aborting $this->reapplyChanges($path); @@ -146,12 +146,12 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa return ' ' . $line; }, explode("\n", $logs))); - $this->io->write(' '.$message); - $this->io->write($logs); + $this->io->writeError(' '.$message); + $this->io->writeError($logs); } } - $this->io->write(''); + $this->io->writeError(''); } /** @@ -159,7 +159,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa */ public function remove(PackageInterface $package, $path) { - $this->io->write(" - Removing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); + $this->io->writeError(" - Removing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); $this->cleanChanges($package, $path, false); if (!$this->filesystem->removeDirectory($path)) { throw new \RuntimeException('Could not completely delete '.$path.', aborting.'); diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 71fa01a41..2fa837615 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -154,11 +154,11 @@ class EventDispatcher $methodName = substr($callable, strpos($callable, '::') + 2); if (!class_exists($className)) { - $this->io->write('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script'); + $this->io->writeError('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script'); continue; } if (!is_callable($callable)) { - $this->io->write('Method '.$callable.' is not callable, can not call '.$event->getName().' script'); + $this->io->writeError('Method '.$callable.' is not callable, can not call '.$event->getName().' script'); continue; } @@ -166,13 +166,13 @@ class EventDispatcher $return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0; } catch (\Exception $e) { $message = "Script %s handling the %s event terminated with an exception"; - $this->io->write(''.sprintf($message, $callable, $event->getName()).''); + $this->io->writeError(''.sprintf($message, $callable, $event->getName()).''); throw $e; } } else { $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor','escape'), $event->getArguments())); if (0 !== ($exitCode = $this->process->execute($callable . ($args === '' ? '' : ' '.$args)))) { - $this->io->write(sprintf('Script %s handling the %s event returned with an error', $callable, $event->getName())); + $this->io->writeError(sprintf('Script %s handling the %s event returned with an error', $callable, $event->getName())); throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode); } diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 3290b51dc..da0a9ef63 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -116,7 +116,7 @@ class Factory $file = new JsonFile($home.'/config.json'); if ($file->exists()) { if ($io && $io->isDebug()) { - $io->write('Loading config file ' . $file->getPath()); + $io->writeError('Loading config file ' . $file->getPath()); } $config->merge($file->read()); } @@ -126,7 +126,7 @@ class Factory $file = new JsonFile($config->get('home').'/auth.json'); if ($file->exists()) { if ($io && $io->isDebug()) { - $io->write('Loading config file ' . $file->getPath()); + $io->writeError('Loading config file ' . $file->getPath()); } $config->merge(array('config' => $file->read())); } @@ -227,12 +227,12 @@ class Factory $config->merge($localConfig); if (isset($composerFile)) { if ($io && $io->isDebug()) { - $io->write('Loading config file ' . $composerFile); + $io->writeError('Loading config file ' . $composerFile); } $localAuthFile = new JsonFile(dirname(realpath($composerFile)) . '/auth.json'); if ($localAuthFile->exists()) { if ($io && $io->isDebug()) { - $io->write('Loading config file ' . $localAuthFile->getPath()); + $io->writeError('Loading config file ' . $localAuthFile->getPath()); } $config->merge(array('config' => $localAuthFile->read())); $config->setAuthConfigSource(new JsonConfigSource($localAuthFile, true)); @@ -362,7 +362,7 @@ class Factory $composer = self::createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), false); } catch (\Exception $e) { if ($io->isDebug()) { - $io->write('Failed to initialize global composer: '.$e->getMessage()); + $io->writeError('Failed to initialize global composer: '.$e->getMessage()); } } diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index 7df26eabf..7145c8da1 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -13,6 +13,7 @@ namespace Composer\IO; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Process\ExecutableFinder; @@ -29,6 +30,7 @@ class ConsoleIO extends BaseIO protected $output; protected $helperSet; protected $lastMessage; + protected $lastMessageErr; private $startTime; /** @@ -94,6 +96,19 @@ class ConsoleIO extends BaseIO * {@inheritDoc} */ public function write($messages, $newline = true) + { + $this->doWrite($messages, $newline, false); + } + + /** + * {@inheritDoc} + */ + public function writeError($messages, $newline = true) + { + $this->doWrite($messages, $newline, true); + } + + private function doWrite($messages, $newline, $stderr) { if (null !== $this->startTime) { $memoryUsage = memory_get_usage() / 1024 / 1024; @@ -102,6 +117,13 @@ class ConsoleIO extends BaseIO return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message); }, (array) $messages); } + + if (true === $stderr && $this->output instanceof ConsoleOutputInterface) { + $this->output->getErrorOutput()->write($messages, $newline); + $this->lastMessageErr = join($newline ? "\n" : '', (array) $messages); + return; + } + $this->output->write($messages, $newline); $this->lastMessage = join($newline ? "\n" : '', (array) $messages); } diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php index f117ce974..a4c4e4f65 100644 --- a/src/Composer/IO/IOInterface.php +++ b/src/Composer/IO/IOInterface.php @@ -64,6 +64,14 @@ interface IOInterface */ public function write($messages, $newline = true); + /** + * Writes a message to the error output. + * + * @param string|array $messages The message as an array of lines or a single string + * @param bool $newline Whether to add a newline or not + */ + public function writeError($messages, $newline = true); + /** * Overwrites a previous message to the output. * diff --git a/src/Composer/IO/NullIO.php b/src/Composer/IO/NullIO.php index f3ecde0cb..f7fbfc753 100644 --- a/src/Composer/IO/NullIO.php +++ b/src/Composer/IO/NullIO.php @@ -66,6 +66,13 @@ class NullIO extends BaseIO { } + /** + * {@inheritDoc} + */ + public function writeError($messages, $newline = true) + { + } + /** * {@inheritDoc} */ diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 72ad6656d..89ecd0643 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -177,7 +177,7 @@ class Installer // purge old require-dev packages to avoid conflicts with the new way of handling dev requirements $devRepo = new InstalledFilesystemRepository(new JsonFile($this->config->get('vendor-dir').'/composer/installed_dev.json')); if ($devRepo->getPackages()) { - $this->io->write('BC Notice: Removing old dev packages to migrate to the new require-dev handling.'); + $this->io->writeError('BC Notice: Removing old dev packages to migrate to the new require-dev handling.'); foreach ($devRepo->getPackages() as $package) { if ($this->installationManager->isPackageInstalled($devRepo, $package)) { $this->installationManager->uninstall($devRepo, new UninstallOperation($package)); @@ -243,7 +243,7 @@ class Installer } } - $this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')'); + $this->io->writeError($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')'); } } @@ -257,7 +257,7 @@ class Installer ? 'Use ' . $package->getReplacementPackage() . ' instead' : 'No replacement was suggested'; - $this->io->write( + $this->io->writeError( sprintf( "Package %s is abandoned, you should avoid using it. %s.", $package->getPrettyName(), @@ -314,16 +314,16 @@ class Installer $this->preferLowest ); if ($updatedLock) { - $this->io->write('Writing lock file'); + $this->io->writeError('Writing lock file'); } } if ($this->dumpAutoloader) { // write autoloader if ($this->optimizeAutoloader) { - $this->io->write('Generating optimized autoload files'); + $this->io->writeError('Generating optimized autoload files'); } else { - $this->io->write('Generating autoload files'); + $this->io->writeError('Generating autoload files'); } $this->autoloadGenerator->setDevMode($this->devMode); @@ -374,7 +374,7 @@ class Installer $this->package->getDevRequires() ); - $this->io->write('Loading composer repositories with package information'); + $this->io->writeError('Loading composer repositories with package information'); // creating repository pool $policy = $this->createPolicy(); @@ -409,7 +409,7 @@ class Installer } if ($this->update) { - $this->io->write('Updating dependencies'.($withDevReqs ? ' (including require-dev)' : '').''); + $this->io->writeError('Updating dependencies'.($withDevReqs ? ' (including require-dev)' : '').''); $request->updateAll(); @@ -460,10 +460,10 @@ class Installer } } } elseif ($installFromLock) { - $this->io->write('Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').' from lock file'); + $this->io->writeError('Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').' from lock file'); if (!$this->locker->isFresh()) { - $this->io->write('Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.'); + $this->io->writeError('Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.'); } foreach ($lockedRepository->getPackages() as $package) { @@ -480,7 +480,7 @@ class Installer $request->install($link->getTarget(), $link->getConstraint()); } } else { - $this->io->write('Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').''); + $this->io->writeError('Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').''); if ($withDevReqs) { $links = array_merge($this->package->getRequires(), $this->package->getDevRequires()); @@ -503,8 +503,8 @@ class Installer $operations = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations); } catch (SolverProblemsException $e) { - $this->io->write('Your requirements could not be resolved to an installable set of packages.'); - $this->io->write($e->getMessage()); + $this->io->writeError('Your requirements could not be resolved to an installable set of packages.'); + $this->io->writeError($e->getMessage()); return max(1, $e->getCode()); } @@ -514,7 +514,7 @@ class Installer // execute operations if (!$operations) { - $this->io->write('Nothing to install or update'); + $this->io->writeError('Nothing to install or update'); } $operations = $this->movePluginsToFront($operations); @@ -553,8 +553,8 @@ class Installer && $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference() ) { if ($this->io->isDebug()) { - $this->io->write(' - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version'); - $this->io->write(''); + $this->io->writeError(' - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version'); + $this->io->writeError(''); } continue; @@ -568,11 +568,11 @@ class Installer // output non-alias ops in dry run, output alias ops in debug verbosity if ($this->dryRun && false === strpos($operation->getJobType(), 'Alias')) { - $this->io->write(' - ' . $operation); - $this->io->write(''); + $this->io->writeError(' - ' . $operation); + $this->io->writeError(''); } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) { - $this->io->write(' - ' . $operation); - $this->io->write(''); + $this->io->writeError(' - ' . $operation); + $this->io->writeError(''); } $this->installationManager->execute($localRepo, $operation); @@ -583,12 +583,12 @@ class Installer if ($reason instanceof Rule) { switch ($reason->getReason()) { case Rule::RULE_JOB_INSTALL: - $this->io->write(' REASON: Required by root: '.$reason->getPrettyString($pool)); - $this->io->write(''); + $this->io->writeError(' REASON: Required by root: '.$reason->getPrettyString($pool)); + $this->io->writeError(''); break; case Rule::RULE_PACKAGE_REQUIRES: - $this->io->write(' REASON: '.$reason->getPrettyString($pool)); - $this->io->write(''); + $this->io->writeError(' REASON: '.$reason->getPrettyString($pool)); + $this->io->writeError(''); break; } } @@ -1001,7 +1001,7 @@ class Installer } if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock'))) { - $this->io->write('Package "' . $packageName . '" listed for update is not installed. Ignoring.'); + $this->io->writeError('Package "' . $packageName . '" listed for update is not installed. Ignoring.'); } foreach ($depPackages as $depPackage) { diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 05cd420d7..5d6180bb0 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -197,7 +197,7 @@ class LibraryInstaller implements InstallerInterface foreach ($binaries as $bin) { $binPath = $this->getInstallPath($package).'/'.$bin; if (!file_exists($binPath)) { - $this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package'); + $this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package'); continue; } @@ -216,7 +216,7 @@ class LibraryInstaller implements InstallerInterface // is a fresh install of the vendor. @chmod($link, 0777 & ~umask()); } - $this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file'); + $this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file'); continue; } if (defined('PHP_WINDOWS_VERSION_BUILD')) { @@ -226,7 +226,7 @@ class LibraryInstaller implements InstallerInterface @chmod($link, 0777 & ~umask()); $link .= '.bat'; if (file_exists($link)) { - $this->io->write(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); + $this->io->writeError(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); } } if (!file_exists($link)) { diff --git a/src/Composer/Installer/PearInstaller.php b/src/Composer/Installer/PearInstaller.php index fd3bbd976..146e68b95 100644 --- a/src/Composer/Installer/PearInstaller.php +++ b/src/Composer/Installer/PearInstaller.php @@ -76,7 +76,7 @@ class PearInstaller extends LibraryInstaller $pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars); if ($this->io->isVerbose()) { - $this->io->write(' Cleaning up'); + $this->io->writeError(' Cleaning up'); } $this->filesystem->unlink($packageArchive); } diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 9e4c12391..96b743de1 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -127,7 +127,7 @@ class PluginManager } if (!$requiresComposer->matches(new VersionConstraint('==', $this->versionParser->normalize(PluginInterface::PLUGIN_API_VERSION)))) { - $this->io->write("The plugin ".$package->getName()." requires a version of composer-plugin-api that does not match your composer installation. You may need to run composer update with the '--no-plugins' option."); + $this->io->writeError("The plugin ".$package->getName()." requires a version of composer-plugin-api that does not match your composer installation. You may need to run composer update with the '--no-plugins' option."); } $this->registerPackage($package); diff --git a/src/Composer/Repository/ArtifactRepository.php b/src/Composer/Repository/ArtifactRepository.php index 38936e40a..2bb518b8f 100644 --- a/src/Composer/Repository/ArtifactRepository.php +++ b/src/Composer/Repository/ArtifactRepository.php @@ -60,14 +60,14 @@ class ArtifactRepository extends ArrayRepository $package = $this->getComposerInformation($file); if (!$package) { if ($io->isVerbose()) { - $io->write("File {$file->getBasename()} doesn't seem to hold a package"); + $io->writeError("File {$file->getBasename()} doesn't seem to hold a package"); } continue; } if ($io->isVerbose()) { $template = 'Found package %s (%s) in file %s'; - $io->write(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename())); + $io->writeError(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename())); } $this->addPackage($package); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index ad3c9996b..bd84ae187 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -434,7 +434,7 @@ class ComposerRepository extends ArrayRepository } if (!empty($data['warning'])) { - $this->io->write('Warning from '.$this->url.': '.$data['warning'].''); + $this->io->writeError('Warning from '.$this->url.': '.$data['warning'].''); } if (!empty($data['providers-lazy-url'])) { @@ -613,8 +613,8 @@ class ComposerRepository extends ArrayRepository if ($cacheKey && ($contents = $this->cache->read($cacheKey))) { if (!$this->degradedMode) { - $this->io->write(''.$e->getMessage().''); - $this->io->write(''.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date'); + $this->io->writeError(''.$e->getMessage().''); + $this->io->writeError(''.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date'); } $this->degradedMode = true; $data = JsonFile::parseJson($contents, $this->cache->getRoot().$cacheKey); diff --git a/src/Composer/Repository/PearRepository.php b/src/Composer/Repository/PearRepository.php index 6086df1ed..1f882eb80 100644 --- a/src/Composer/Repository/PearRepository.php +++ b/src/Composer/Repository/PearRepository.php @@ -66,13 +66,13 @@ class PearRepository extends ArrayRepository { parent::initialize(); - $this->io->write('Initializing PEAR repository '.$this->url); + $this->io->writeError('Initializing PEAR repository '.$this->url); $reader = new ChannelReader($this->rfs); try { $channelInfo = $reader->read($this->url); } catch (\Exception $e) { - $this->io->write('PEAR repository from '.$this->url.' could not be loaded. '.$e->getMessage().''); + $this->io->writeError('PEAR repository from '.$this->url.' could not be loaded. '.$e->getMessage().''); return; } @@ -98,7 +98,7 @@ class PearRepository extends ArrayRepository $normalizedVersion = $versionParser->normalize($version); } catch (\UnexpectedValueException $e) { if ($this->io->isVerbose()) { - $this->io->write('Could not load '.$packageDefinition->getPackageName().' '.$version.': '.$e->getMessage()); + $this->io->writeError('Could not load '.$packageDefinition->getPackageName().' '.$version.': '.$e->getMessage()); } continue; } diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php index 68389dc33..199fc48c8 100644 --- a/src/Composer/Repository/Vcs/GitBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -149,7 +149,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface if (!extension_loaded('openssl')) { if ($io->isVerbose()) { - $io->write('Skipping Bitbucket git driver for '.$url.' because the OpenSSL PHP extension is missing.'); + $io->writeError('Skipping Bitbucket git driver for '.$url.' because the OpenSSL PHP extension is missing.'); } return false; diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index a859a6869..e9730412d 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -66,7 +66,7 @@ class GitDriver extends VcsDriver }; $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir); } catch (\Exception $e) { - $this->io->write('Failed to update '.$this->url.', package information from this repository may be outdated ('.$e->getMessage().')'); + $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$e->getMessage().')'); } } else { // clean up directory and do a fresh clone into it diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 9dbd21059..fd2e71545 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -266,7 +266,7 @@ class GitHubDriver extends VcsDriver if (!extension_loaded('openssl')) { if ($io->isVerbose()) { - $io->write('Skipping GitHub driver for '.$url.' because the OpenSSL PHP extension is missing.'); + $io->writeError('Skipping GitHub driver for '.$url.' because the OpenSSL PHP extension is missing.'); } return false; @@ -333,7 +333,7 @@ class GitHubDriver extends VcsDriver if (!$this->io->hasAuthentication($this->originUrl)) { if (!$this->io->isInteractive()) { - $this->io->write('GitHub API limit exhausted. Failed to get metadata for the '.$this->url.' repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit'); + $this->io->writeError('GitHub API limit exhausted. Failed to get metadata for the '.$this->url.' repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit'); throw $e; } @@ -344,7 +344,7 @@ class GitHubDriver extends VcsDriver if ($rateLimited) { $rateLimit = $this->getRateLimit($e->getHeaders()); - $this->io->write(sprintf( + $this->io->writeError(sprintf( 'GitHub API limit (%d calls/hr) is exhausted. You are already authorized so you have to wait until %s before doing more requests', $rateLimit['limit'], $rateLimit['reset'] @@ -435,7 +435,7 @@ class GitHubDriver extends VcsDriver } catch (\RuntimeException $e) { $this->gitDriver = null; - $this->io->write('Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your GitHub credentials'); + $this->io->writeError('Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your GitHub credentials'); throw $e; } } diff --git a/src/Composer/Repository/Vcs/HgBitbucketDriver.php b/src/Composer/Repository/Vcs/HgBitbucketDriver.php index cc2b386eb..569b83521 100644 --- a/src/Composer/Repository/Vcs/HgBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/HgBitbucketDriver.php @@ -159,7 +159,7 @@ class HgBitbucketDriver extends VcsDriver if (!extension_loaded('openssl')) { if ($io->isVerbose()) { - $io->write('Skipping Bitbucket hg driver for '.$url.' because the OpenSSL PHP extension is missing.'); + $io->writeError('Skipping Bitbucket hg driver for '.$url.' because the OpenSSL PHP extension is missing.'); } return false; diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index ed8e927b9..06382f039 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -50,7 +50,7 @@ class HgDriver extends VcsDriver // update the repo if it is a valid hg repository if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) { if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) { - $this->io->write('Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')'); + $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')'); } } else { // clean up directory and do a fresh clone into it diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index 6c9dc5d4b..d876ae73e 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -127,14 +127,14 @@ class VcsRepository extends ArrayRepository } } catch (\Exception $e) { if ($verbose) { - $this->io->write('Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().''); + $this->io->writeError('Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().''); } } foreach ($driver->getTags() as $tag => $identifier) { $msg = 'Reading composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $tag . ')'; if ($verbose) { - $this->io->write($msg); + $this->io->writeError($msg); } else { $this->io->overwrite($msg, false); } @@ -144,7 +144,7 @@ class VcsRepository extends ArrayRepository if (!$parsedTag = $this->validateTag($tag)) { if ($verbose) { - $this->io->write('Skipped tag '.$tag.', invalid tag name'); + $this->io->writeError('Skipped tag '.$tag.', invalid tag name'); } continue; } @@ -152,7 +152,7 @@ class VcsRepository extends ArrayRepository try { if (!$data = $driver->getComposerInformation($identifier)) { if ($verbose) { - $this->io->write('Skipped tag '.$tag.', no composer file'); + $this->io->writeError('Skipped tag '.$tag.', no composer file'); } continue; } @@ -173,19 +173,19 @@ class VcsRepository extends ArrayRepository // broken package, version doesn't match tag if ($data['version_normalized'] !== $parsedTag) { if ($verbose) { - $this->io->write('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json'); + $this->io->writeError('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json'); } continue; } if ($verbose) { - $this->io->write('Importing tag '.$tag.' ('.$data['version_normalized'].')'); + $this->io->writeError('Importing tag '.$tag.' ('.$data['version_normalized'].')'); } $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier))); } catch (\Exception $e) { if ($verbose) { - $this->io->write('Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).''); + $this->io->writeError('Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).''); } continue; } @@ -198,14 +198,14 @@ class VcsRepository extends ArrayRepository foreach ($driver->getBranches() as $branch => $identifier) { $msg = 'Reading composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $branch . ')'; if ($verbose) { - $this->io->write($msg); + $this->io->writeError($msg); } else { $this->io->overwrite($msg, false); } if (!$parsedBranch = $this->validateBranch($branch)) { if ($verbose) { - $this->io->write('Skipped branch '.$branch.', invalid name'); + $this->io->writeError('Skipped branch '.$branch.', invalid name'); } continue; } @@ -213,7 +213,7 @@ class VcsRepository extends ArrayRepository try { if (!$data = $driver->getComposerInformation($identifier)) { if ($verbose) { - $this->io->write('Skipped branch '.$branch.', no composer file'); + $this->io->writeError('Skipped branch '.$branch.', no composer file'); } continue; } @@ -230,7 +230,7 @@ class VcsRepository extends ArrayRepository } if ($verbose) { - $this->io->write('Importing branch '.$branch.' ('.$data['version'].')'); + $this->io->writeError('Importing branch '.$branch.' ('.$data['version'].')'); } $packageData = $this->preProcess($driver, $data, $identifier); @@ -241,16 +241,16 @@ class VcsRepository extends ArrayRepository $this->addPackage($package); } catch (TransportException $e) { if ($verbose) { - $this->io->write('Skipped branch '.$branch.', no composer file was found'); + $this->io->writeError('Skipped branch '.$branch.', no composer file was found'); } continue; } catch (\Exception $e) { if (!$verbose) { - $this->io->write(''); + $this->io->writeError(''); } $this->branchErrorOccurred = true; - $this->io->write('Skipped branch '.$branch.', '.$e->getMessage().''); - $this->io->write(''); + $this->io->writeError('Skipped branch '.$branch.', '.$e->getMessage().''); + $this->io->writeError(''); continue; } } diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index c3c5eb02c..f5c87487a 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -122,7 +122,7 @@ class Git } } - $this->io->write(' Authentication required ('.parse_url($url, PHP_URL_HOST).'):'); + $this->io->writeError(' Authentication required ('.parse_url($url, PHP_URL_HOST).'):'); $auth = array( 'username' => $this->io->ask(' Username: ', $defaultUsername), 'password' => $this->io->askAndHideAnswer(' Password: '), diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php index 6008dc062..a994de97b 100644 --- a/src/Composer/Util/GitHub.php +++ b/src/Composer/Util/GitHub.php @@ -77,11 +77,11 @@ class GitHub public function authorizeOAuthInteractively($originUrl, $message = null) { if ($message) { - $this->io->write($message); + $this->io->writeError($message); } - $this->io->write(sprintf('A token will be created and stored in "%s", your password will never be stored', $this->config->getAuthConfigSource()->getName())); - $this->io->write('To revoke access to this token you can visit https://github.com/settings/applications'); + $this->io->writeError(sprintf('A token will be created and stored in "%s", your password will never be stored', $this->config->getAuthConfigSource()->getName())); + $this->io->writeError('To revoke access to this token you can visit https://github.com/settings/applications'); $otp = null; $attemptCounter = 0; @@ -105,13 +105,13 @@ class GitHub } if (401 === $e->getCode()) { - $this->io->write('Bad credentials.'); + $this->io->writeError('Bad credentials.'); } else { - $this->io->write('Maximum number of login attempts exceeded. Please try again later.'); + $this->io->writeError('Maximum number of login attempts exceeded. Please try again later.'); } - $this->io->write('You can also manually create a personal token at https://github.com/settings/applications'); - $this->io->write('Add it using "composer config github-oauth.github.com "'); + $this->io->writeError('You can also manually create a personal token at https://github.com/settings/applications'); + $this->io->writeError('Add it using "composer config github-oauth.github.com "'); continue; } @@ -166,7 +166,7 @@ class GitHub ) )); - $this->io->write('Token successfully created'); + $this->io->writeError('Token successfully created'); return JsonFile::parseJson($json); } @@ -184,14 +184,14 @@ class GitHub list($required, $method) = array_map('trim', explode(';', substr(strstr($headers[$key], ':'), 1))); if ('required' === $required) { - $this->io->write('Two-factor Authentication'); + $this->io->writeError('Two-factor Authentication'); if ('app' === $method) { - $this->io->write('Open the two-factor authentication app on your device to view your authentication code and verify your identity.'); + $this->io->writeError('Open the two-factor authentication app on your device to view your authentication code and verify your identity.'); } if ('sms' === $method) { - $this->io->write('You have been sent an SMS message with an authentication code to verify your identity.'); + $this->io->writeError('You have been sent an SMS message with an authentication code to verify your identity.'); } return $this->io->ask('Authentication Code: '); diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 46dafb0ae..38f5bba00 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -45,7 +45,7 @@ class ProcessExecutor { if ($this->io && $this->io->isDebug()) { $safeCommand = preg_replace('{(://[^:/\s]+:)[^@\s/]+}i', '$1****', $command); - $this->io->write('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand); + $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand); } // make sure that null translate to the proper directory in case the dir is a symlink diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 455bda92e..ae1938323 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -146,7 +146,7 @@ class RemoteFilesystem $options = $this->getOptionsForUrl($originUrl, $additionalOptions); if ($this->io->isDebug()) { - $this->io->write((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl); + $this->io->writeError((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl); } if (isset($options['github-token'])) { $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['github-token']; @@ -158,7 +158,7 @@ class RemoteFilesystem $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { - $this->io->write(" Downloading: connection...", false); + $this->io->writeError(" Downloading: connection...", false); } $errorMessage = ''; diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index 4949aa271..af7dc6cbd 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -111,7 +111,7 @@ class Svn } $output .= $buffer; if ($verbose) { - $io->write($buffer, false); + $io->writeError($buffer, false); } }; $status = $this->process->execute($svnCommand, $handler, $cwd); @@ -169,7 +169,7 @@ class Svn ); } - $this->io->write("The Subversion server ({$this->url}) requested credentials:"); + $this->io->writeError("The Subversion server ({$this->url}) requested credentials:"); $this->hasAuth = true; $this->credentials['username'] = $this->io->ask("Username: "); diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index c99022671..0f1a076b4 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -29,7 +29,7 @@ class ApplicationTest extends TestCase ->will($this->returnValue('list')); $outputMock->expects($this->once()) - ->method("writeln") + ->method("write") ->with($this->equalTo(sprintf('Warning: This development build of composer is over 30 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF']))); if (!defined('COMPOSER_DEV_WARNING_TIME')) { diff --git a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php index 1ef68d459..81f99e57b 100644 --- a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php +++ b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php @@ -128,7 +128,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase $msg = ''; $io->expects($this->once()) - ->method('write') + ->method('writeError') ->will($this->returnCallback(function ($text) use (&$msg) { $msg = $text; })); diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index 3e2bce2b4..2c113b5ae 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -120,7 +120,7 @@ class PerforceDownloaderTest extends \PHPUnit_Framework_TestCase $ref = 'SOURCE_REF@123'; $label = 123; $this->package->expects($this->once())->method('getSourceReference')->will($this->returnValue($ref)); - $this->io->expects($this->once())->method('write')->with($this->stringContains('Cloning '.$ref)); + $this->io->expects($this->once())->method('writeError')->with($this->stringContains('Cloning '.$ref)); $perforceMethods = array('setStream', 'p4Login', 'writeP4ClientSpec', 'connectClient', 'syncCodeBase', 'cleanupClientSpec'); $perforce = $this->getMockBuilder('Composer\Util\Perforce', $perforceMethods)->disableOriginalConstructor()->getMock(); $perforce->expects($this->at(0))->method('initializePath')->with($this->equalTo($this->testPath)); @@ -143,7 +143,7 @@ class PerforceDownloaderTest extends \PHPUnit_Framework_TestCase $ref = 'SOURCE_REF'; $label = null; $this->package->expects($this->once())->method('getSourceReference')->will($this->returnValue($ref)); - $this->io->expects($this->once())->method('write')->with($this->stringContains('Cloning '.$ref)); + $this->io->expects($this->once())->method('writeError')->with($this->stringContains('Cloning '.$ref)); $perforceMethods = array('setStream', 'p4Login', 'writeP4ClientSpec', 'connectClient', 'syncCodeBase', 'cleanupClientSpec'); $perforce = $this->getMockBuilder('Composer\Util\Perforce', $perforceMethods)->disableOriginalConstructor()->getMock(); $perforce->expects($this->at(0))->method('initializePath')->with($this->equalTo($this->testPath)); diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php index c750e82a9..06d9c652d 100644 --- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php +++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php @@ -33,7 +33,7 @@ class EventDispatcherTest extends TestCase ), $io); $io->expects($this->once()) - ->method('write') + ->method('writeError') ->with('Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception'); $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); @@ -189,7 +189,7 @@ class EventDispatcherTest extends TestCase ->will($this->returnValue($listener)); $io->expects($this->once()) - ->method('write') + ->method('writeError') ->with($this->equalTo('Script '.$code.' handling the post-install-cmd event returned with an error')); $this->setExpectedException('RuntimeException'); diff --git a/tests/Composer/Test/Fixtures/functional/create-project-command.test b/tests/Composer/Test/Fixtures/functional/create-project-command.test index 2e4b2762a..c59950274 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-command.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-command.test @@ -1,6 +1,6 @@ --RUN-- create-project seld/jsonlint %testDir% 1.0.0 --prefer-source -n ---EXPECT-- +--EXPECT-ERROR-- Installing seld/jsonlint (1.0.0) - Installing seld/jsonlint (1.0.0) Cloning 3b4bc2a96ff5d3fe6866bfe9dd0c845246705791 diff --git a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test index 0e5188e41..fa7ecbe32 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test @@ -1,4 +1,4 @@ --RUN-- create-project --repository-url=packages.json -v seld/jsonlint %testDir% dev-master ---EXPECT-REGEX-- +--EXPECT-ERROR-REGEX-- {^Installing seld/jsonlint \(dev-master [a-f0-9]{40}\)} diff --git a/tests/Composer/Test/IO/ConsoleIOTest.php b/tests/Composer/Test/IO/ConsoleIOTest.php index 417ff260c..0edd34d99 100644 --- a/tests/Composer/Test/IO/ConsoleIOTest.php +++ b/tests/Composer/Test/IO/ConsoleIOTest.php @@ -49,6 +49,22 @@ class ConsoleIOTest extends TestCase $consoleIO->write('some information about something', false); } + public function testWriteError() + { + $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface'); + $outputMock = $this->getMock('Symfony\Component\Console\Output\ConsoleOutputInterface'); + $outputMock->expects($this->once()) + ->method('getErrorOutput') + ->willReturn($outputMock); + $outputMock->expects($this->once()) + ->method('write') + ->with($this->equalTo('some information about something'), $this->equalTo(false)); + $helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet'); + + $consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock); + $consoleIO->writeError('some information about something', false); + } + public function testWriteWithMultipleLineStringWhenDebugging() { $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface'); diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 0ec1f5972..7fa85d76d 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -149,11 +149,15 @@ class InstallerTest extends TestCase $output = null; $io = $this->getMock('Composer\IO\IOInterface'); + $callback = function ($text, $newline) use (&$output) { + $output .= $text . ($newline ? "\n" : ""); + }; $io->expects($this->any()) ->method('write') - ->will($this->returnCallback(function ($text, $newline) use (&$output) { - $output .= $text . ($newline ? "\n" : ""); - })); + ->will($this->returnCallback($callback)); + $io->expects($this->any()) + ->method('writeError') + ->will($this->returnCallback($callback)); $composer = FactoryMock::create($io, $composerConfig); @@ -195,10 +199,7 @@ class InstallerTest extends TestCase $composer->setAutoloadGenerator($autoloadGenerator); $composer->setEventDispatcher($eventDispatcher); - $installer = Installer::create( - $io, - $composer - ); + $installer = Installer::create($io, $composer); $application = new Application; $application->get('install')->setCode(function ($input, $output) use ($installer) { diff --git a/tests/Composer/Test/Util/GitHubTest.php b/tests/Composer/Test/Util/GitHubTest.php index 1f30c44a0..488507ec3 100644 --- a/tests/Composer/Test/Util/GitHubTest.php +++ b/tests/Composer/Test/Util/GitHubTest.php @@ -34,7 +34,7 @@ class GitHubTest extends \PHPUnit_Framework_TestCase $io = $this->getIOMock(); $io ->expects($this->at(0)) - ->method('write') + ->method('writeError') ->with($this->message) ; $io From ec434e457687a4d4cbacf54cdce05f581e50dddf Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 18 Feb 2015 10:01:24 +0100 Subject: [PATCH 37/83] Formatting only --- src/Composer/IO/BufferIO.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Composer/IO/BufferIO.php b/src/Composer/IO/BufferIO.php index fc675ce70..581680b7c 100644 --- a/src/Composer/IO/BufferIO.php +++ b/src/Composer/IO/BufferIO.php @@ -23,16 +23,19 @@ use Symfony\Component\Console\Helper\HelperSet; class BufferIO extends ConsoleIO { /** - * @param string $input - * @param int $verbosity + * @param string $input + * @param int $verbosity * @param OutputFormatterInterface $formatter */ - public function __construct($input = '', $verbosity = null, OutputFormatterInterface $formatter = null) - { + public function __construct( + $input = '', + $verbosity = StreamOutput::VERBOSITY_NORMAL, + OutputFormatterInterface $formatter = null + ) { $input = new StringInput($input); $input->setInteractive(false); - $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity === null ? StreamOutput::VERBOSITY_NORMAL : $verbosity, !empty($formatter), $formatter); + $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, !empty($formatter), $formatter); parent::__construct($input, $output, new HelperSet(array())); } From 3c7a617753ccd36a66c4b5c6faa09b562ddbd8e8 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 18 Feb 2015 10:03:45 +0100 Subject: [PATCH 38/83] overwriteError + ask[X]() to stderr --- src/Composer/IO/ConsoleIO.php | 92 +++++++++++++++++++++++++++------ src/Composer/IO/IOInterface.php | 9 ++++ src/Composer/IO/NullIO.php | 7 +++ 3 files changed, 91 insertions(+), 17 deletions(-) diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index 7145c8da1..0ab617a94 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -108,6 +108,11 @@ class ConsoleIO extends BaseIO $this->doWrite($messages, $newline, true); } + /** + * @param array $messages + * @param boolean $newline + * @param boolean $stderr + */ private function doWrite($messages, $newline, $stderr) { if (null !== $this->startTime) { @@ -133,12 +138,38 @@ class ConsoleIO extends BaseIO */ public function overwrite($messages, $newline = true, $size = null) { - if (!$this->output->isDecorated()) { + $this->doOverwrite($messages, $newline, $size, false); + } + + /** + * {@inheritDoc} + */ + public function overwriteError($messages, $newline = true, $size = null) + { + $this->doOverwrite($messages, $newline, $size, true); + } + + /** + * @param array $messages + * @param boolean $newline + * @param integer $size + * @param boolean $stderr + */ + private function doOverwrite($messages, $newline, $size, $stderr) + { + if (true === $stderr && $this->output instanceof ConsoleOutputInterface) { + $output = $this->output->getErrorOutput(); + } else { + $output = $this->output; + } + + if (!$output->isDecorated()) { if (!$messages) { return; } - return $this->write($messages, count($messages) === 1 || $newline); + $this->doWrite($messages, count($messages) === 1 || $newline, $stderr); + return; } // messages can be an array, let's convert it to string anyway @@ -147,24 +178,24 @@ class ConsoleIO extends BaseIO // since overwrite is supposed to overwrite last message... if (!isset($size)) { // removing possible formatting of lastMessage with strip_tags - $size = strlen(strip_tags($this->lastMessage)); + $size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage)); } // ...let's fill its length with backspaces - $this->write(str_repeat("\x08", $size), false); + $this->doWrite(str_repeat("\x08", $size), false, $stderr); // write the new message - $this->write($messages, false); + $this->doWrite($messages, false, $stderr); $fill = $size - strlen(strip_tags($messages)); if ($fill > 0) { // whitespace whatever has left - $this->write(str_repeat(' ', $fill), false); + $this->doWrite(str_repeat(' ', $fill), false, $stderr); // move the cursor back - $this->write(str_repeat("\x08", $fill), false); + $this->doWrite(str_repeat("\x08", $fill), false, $stderr); } if ($newline) { - $this->write(''); + $this->doWrite('', true, $stderr); } $this->lastMessage = $messages; } @@ -174,7 +205,16 @@ class ConsoleIO extends BaseIO */ public function ask($question, $default = null) { - return $this->helperSet->get('dialog')->ask($this->output, $question, $default); + $output = $this->output; + + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */ + $dialog = $this->helperSet->get('dialog'); + + return $dialog->ask($output, $question, $default); } /** @@ -182,7 +222,16 @@ class ConsoleIO extends BaseIO */ public function askConfirmation($question, $default = true) { - return $this->helperSet->get('dialog')->askConfirmation($this->output, $question, $default); + $output = $this->output; + + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */ + $dialog = $this->helperSet->get('dialog'); + + return $dialog->askConfirmation($output, $question, $default); } /** @@ -190,7 +239,16 @@ class ConsoleIO extends BaseIO */ public function askAndValidate($question, $validator, $attempts = false, $default = null) { - return $this->helperSet->get('dialog')->askAndValidate($this->output, $question, $validator, $attempts, $default); + $output = $this->output; + + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */ + $dialog = $this->helperSet->get('dialog'); + + return $dialog->askAndValidate($output, $question, $validator, $attempts, $default); } /** @@ -204,9 +262,9 @@ class ConsoleIO extends BaseIO // use bash if it's present if ($finder->find('bash') && $finder->find('stty')) { - $this->write($question, false); + $this->writeError($question, false); $value = rtrim(shell_exec('bash -c "stty -echo; read -n0 discard; read -r mypassword; stty echo; echo $mypassword"')); - $this->write(''); + $this->writeError(''); return $value; } @@ -230,9 +288,9 @@ class ConsoleIO extends BaseIO $exe = $tmpExe; } - $this->write($question, false); + $this->writeError($question, false); $value = rtrim(shell_exec($exe)); - $this->write(''); + $this->writeError(''); // clean up if (isset($tmpExe)) { @@ -252,11 +310,11 @@ class ConsoleIO extends BaseIO } } if (isset($shell)) { - $this->write($question, false); + $this->writeError($question, false); $readCmd = ($shell === 'csh') ? 'set mypassword = $<' : 'read -r mypassword'; $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); $value = rtrim(shell_exec($command)); - $this->write(''); + $this->writeError(''); return $value; } diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php index a4c4e4f65..0fd63fe4a 100644 --- a/src/Composer/IO/IOInterface.php +++ b/src/Composer/IO/IOInterface.php @@ -81,6 +81,15 @@ interface IOInterface */ public function overwrite($messages, $newline = true, $size = null); + /** + * Overwrites a previous message to the error output. + * + * @param string|array $messages The message as an array of lines or a single string + * @param bool $newline Whether to add a newline or not + * @param integer $size The size of line + */ + public function overwriteError($messages, $newline = true, $size = null); + /** * Asks a question to the user. * diff --git a/src/Composer/IO/NullIO.php b/src/Composer/IO/NullIO.php index f7fbfc753..1a88395d3 100644 --- a/src/Composer/IO/NullIO.php +++ b/src/Composer/IO/NullIO.php @@ -80,6 +80,13 @@ class NullIO extends BaseIO { } + /** + * {@inheritDoc} + */ + public function overwriteError($messages, $newline = true, $size = 80) + { + } + /** * {@inheritDoc} */ From 3d329622d7c82c745a74f920016ba197a173a2b3 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 18 Feb 2015 10:04:39 +0100 Subject: [PATCH 39/83] overwrite -> overwriteError --- src/Composer/Repository/VcsRepository.php | 8 ++++---- src/Composer/Util/RemoteFilesystem.php | 6 +++--- tests/Composer/Test/Util/RemoteFilesystemTest.php | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index d876ae73e..034260d0c 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -136,7 +136,7 @@ class VcsRepository extends ArrayRepository if ($verbose) { $this->io->writeError($msg); } else { - $this->io->overwrite($msg, false); + $this->io->overwriteError($msg, false); } // strip the release- prefix from tags if present @@ -192,7 +192,7 @@ class VcsRepository extends ArrayRepository } if (!$verbose) { - $this->io->overwrite('', false); + $this->io->overwriteError('', false); } foreach ($driver->getBranches() as $branch => $identifier) { @@ -200,7 +200,7 @@ class VcsRepository extends ArrayRepository if ($verbose) { $this->io->writeError($msg); } else { - $this->io->overwrite($msg, false); + $this->io->overwriteError($msg, false); } if (!$parsedBranch = $this->validateBranch($branch)) { @@ -257,7 +257,7 @@ class VcsRepository extends ArrayRepository $driver->cleanup(); if (!$verbose) { - $this->io->overwrite('', false); + $this->io->overwriteError('', false); } if (!$this->getPackages()) { diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index ae1938323..9e6b50d74 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -228,7 +228,7 @@ class RemoteFilesystem } if ($this->progress && !$this->retry) { - $this->io->overwrite(" Downloading: 100%"); + $this->io->overwriteError(" Downloading: 100%"); } // handle copy command if download was successful @@ -329,7 +329,7 @@ class RemoteFilesystem if ((0 === $progression % 5) && $progression !== $this->lastProgress) { $this->lastProgress = $progression; - $this->io->overwrite(" Downloading: $progression%", false); + $this->io->overwriteError(" Downloading: $progression%", false); } } break; @@ -371,7 +371,7 @@ class RemoteFilesystem throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus); } - $this->io->overwrite(' Authentication required ('.parse_url($this->fileUrl, PHP_URL_HOST).'):'); + $this->io->overwriteError(' Authentication required ('.parse_url($this->fileUrl, PHP_URL_HOST).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); $this->io->setAuthentication($this->originUrl, $username, $password); diff --git a/tests/Composer/Test/Util/RemoteFilesystemTest.php b/tests/Composer/Test/Util/RemoteFilesystemTest.php index bbeba908e..04502ebdc 100644 --- a/tests/Composer/Test/Util/RemoteFilesystemTest.php +++ b/tests/Composer/Test/Util/RemoteFilesystemTest.php @@ -119,7 +119,7 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase $io = $this->getMock('Composer\IO\IOInterface'); $io ->expects($this->once()) - ->method('overwrite') + ->method('overwriteError') ; $fs = new RemoteFilesystem($io); From fa3ea2a62676106ee64a177145c867ab9fe2947e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 25 Feb 2015 11:54:18 +0100 Subject: [PATCH 40/83] remove unused method argument Unlike the `TableHelper`, the `render()` method of the `Table` class does not make use of an `$output` argument. The actual `OutputInterface` to send the table to is passed in the constructor instead. --- src/Composer/Command/LicensesCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 757de6d87..176b1bb61 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -83,7 +83,7 @@ EOT implode(', ', $package->getLicense()) ?: 'none', )); } - $table->render($output); + $table->render(); break; case 'json': From 3ba581f0dfa9560e04dcfa0a90ff60c26f20edb3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 25 Feb 2015 16:23:27 +0000 Subject: [PATCH 41/83] Improve error messages for required hhvm/php versions, fixes #3767 --- src/Composer/DependencyResolver/Pool.php | 5 +++++ src/Composer/DependencyResolver/Problem.php | 13 +++++++++++++ src/Composer/DependencyResolver/Rule.php | 10 +++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index e0d2d8a13..0063a44ba 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -65,6 +65,11 @@ class Pool } $this->stabilityFlags = $stabilityFlags; $this->filterRequires = $filterRequires; + foreach ($filterRequires as $name => $constraint) { + if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) { + unset($this->filterRequires[$name]); + } + } } public function setWhitelist($whitelist) diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 9373a7b7b..b1d2bb9b4 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -87,6 +87,19 @@ class Problem } if ($job && $job['cmd'] === 'install' && empty($packages)) { + // handle php/hhvm + if ($job['packageName'] === 'php' || $job['packageName'] === 'php-64bit' || $job['packageName'] === 'hhvm') { + $msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but '; + + if (defined('HHVM_VERSION')) { + return $msg . 'your HHVM version does not satisfy that requirement.'; + } elseif ($job['packageName'] === 'hhvm') { + return $msg . 'you are running this with PHP and not HHVM.'; + } + + return $msg . 'your PHP version does not satisfy that requirement.'; + } + // handle php extensions if (0 === stripos($job['packageName'], 'ext-')) { $ext = substr($job['packageName'], 4); diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php index cba9400ef..bdb82afca 100644 --- a/src/Composer/DependencyResolver/Rule.php +++ b/src/Composer/DependencyResolver/Rule.php @@ -217,7 +217,15 @@ class Rule $targetName = $this->reasonData->getTarget(); // handle php extensions - if (0 === strpos($targetName, 'ext-')) { + if ($targetName === 'php' || $targetName === 'php-64bit' || $targetName === 'hhvm') { + if (defined('HHVM_VERSION')) { + $text .= ' -> your HHVM version does not satisfy that requirement.'; + } elseif ($targetName === 'hhvm') { + $text .= ' -> you are running this with PHP and not HHVM.'; + } else { + $text .= ' -> your PHP version does not satisfy that requirement.'; + } + } elseif (0 === strpos($targetName, 'ext-')) { $ext = substr($targetName, 4); $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system'; From 7b635f835decab262e089b60c9d09621f5960345 Mon Sep 17 00:00:00 2001 From: Raphael Antonmattei Date: Wed, 25 Feb 2015 11:46:36 -0500 Subject: [PATCH 42/83] VCS section: add requirements for the branch name If you want to use a custom branch in your requirements in your `composer.json`, that branch must be prefixed with "dev-" or you'll get an error: ```sh [UnexpectedValueException] Could not parse version constraint some-branch: Invalid version string "some-branch". ``` It took me a while to find that info, so I figured I'd rather edit the doc. Let me know. --- doc/05-repositories.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 2dd5e24d5..3b0bd4d38 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -234,7 +234,7 @@ project to use the patched version. If the library is on GitHub (this is the case most of the time), you can simply fork it there and push your changes to your fork. After that you update the project's `composer.json`. All you have to do is add your fork as a repository and update the version constraint to -point to your custom branch. For version constraint naming conventions see +point to your custom branch. Your custom branch name must be prefixed with `"dev-"`. For version constraint naming conventions see [Libraries](02-libraries.md) for more information. Example assuming you patched monolog to fix a bug in the `bugfix` branch: From c573ae57810e98f60e810e5d1a920a51c12c8ebc Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 25 Feb 2015 17:48:01 +0000 Subject: [PATCH 43/83] Add missing LICENSE files from dependencies, fixes #3776 --- src/Composer/Compiler.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index 8697d8caf..b5db79304 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -102,10 +102,13 @@ class Compiler $finder->files() ->ignoreVCS(true) ->name('*.php') + ->name('LICENSE') ->exclude('Tests') + ->exclude('tests') + ->exclude('docs') ->in(__DIR__.'/../../vendor/symfony/') - ->in(__DIR__.'/../../vendor/seld/jsonlint/src/') - ->in(__DIR__.'/../../vendor/justinrainbow/json-schema/src/') + ->in(__DIR__.'/../../vendor/seld/jsonlint/') + ->in(__DIR__.'/../../vendor/justinrainbow/json-schema/') ; foreach ($finder as $file) { From bcb5e479b7640b0ae4139600e36fa3ee2d626485 Mon Sep 17 00:00:00 2001 From: Edward Hartwell Goose Date: Wed, 25 Feb 2015 18:41:13 +0000 Subject: [PATCH 44/83] Fix reference to getIO as per #3777 --- src/Composer/Console/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index f318832bc..2ccaec890 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -151,7 +151,7 @@ class Application extends BaseApplication } if (isset($startTime)) { - $this->getIO->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s'); + $this->getIO()->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s'); } return $result; From 0c775e997e0747a561cacf67716e0948511877fa Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 25 Feb 2015 18:47:31 +0000 Subject: [PATCH 45/83] Fallback to https directly if ssh proto is disabled on github private repos, fixes #2786 --- src/Composer/Util/Git.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index f5c87487a..00c909b9d 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -52,9 +52,10 @@ class Git } } + $protocols = $this->config->get('github-protocols'); + // public github, autoswitch protocols if (preg_match('{^(?:https?|git)://'.self::getGitHubDomainsRegex($this->config).'/(.*)}', $url, $match)) { - $protocols = $this->config->get('github-protocols'); if (!is_array($protocols)) { throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols)); } @@ -79,8 +80,11 @@ class Git $this->throwException('Failed to clone ' . self::sanitizeUrl($url) .' via '.implode(', ', $protocols).' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url); } + // if we have a private github url and the ssh protocol is disabled then we skip it and directly fallback to https + $bypassSshForGitHub = preg_match('{^git@'.self::getGitHubDomainsRegex($this->config).':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true); + $command = call_user_func($commandCallable, $url); - if (0 !== $this->process->execute($command, $ignoredOutput, $cwd)) { + if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) { // private github repository without git access, try https with auth if (preg_match('{^git@'.self::getGitHubDomainsRegex($this->config).':(.+?)\.git$}i', $url, $match)) { if (!$this->io->hasAuthentication($match[1])) { From 2eb69f120e5ca704e28fedbb3240ef84e61eb419 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 25 Feb 2015 19:30:51 +0000 Subject: [PATCH 46/83] Move check to follow the previous code change --- src/Composer/Util/Git.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 00c909b9d..e965384e7 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -53,12 +53,12 @@ class Git } $protocols = $this->config->get('github-protocols'); + if (!is_array($protocols)) { + throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols)); + } // public github, autoswitch protocols if (preg_match('{^(?:https?|git)://'.self::getGitHubDomainsRegex($this->config).'/(.*)}', $url, $match)) { - if (!is_array($protocols)) { - throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols)); - } $messages = array(); foreach ($protocols as $protocol) { if ('ssh' === $protocol) { From 4d665f59b0dad088025cdcefc544dd9ad7f73b85 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 27 Feb 2015 12:20:42 +0000 Subject: [PATCH 47/83] Create lock if we only have platform dependencies --- src/Composer/Package/Locker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 40ff8907c..171cf0362 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -258,7 +258,10 @@ class Locker $lock['packages-dev'] = $this->lockPackages($devPackages); } - if (empty($lock['packages']) && empty($lock['packages-dev'])) { + $lock['platform'] = $platformReqs; + $lock['platform-dev'] = $platformDevReqs; + + if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) { if ($this->lockFile->exists()) { unlink($this->lockFile->getPath()); } @@ -266,9 +269,6 @@ class Locker return false; } - $lock['platform'] = $platformReqs; - $lock['platform-dev'] = $platformDevReqs; - if (!$this->isLocked() || $lock !== $this->getLockData()) { $this->lockFile->write($lock); $this->lockDataCache = null; From c7b0628d937f89fec8f4b498b5fd670e6caf6408 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 27 Feb 2015 12:27:56 +0000 Subject: [PATCH 48/83] Fix tests --- .../Test/Fixtures/functional/create-project-command.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Composer/Test/Fixtures/functional/create-project-command.test b/tests/Composer/Test/Fixtures/functional/create-project-command.test index c59950274..6282e6357 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-command.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-command.test @@ -9,4 +9,5 @@ Created project in %testDir% Loading composer repositories with package information Installing dependencies (including require-dev) Nothing to install or update +Writing lock file Generating autoload files From 45b1f356c24d87788a339f6a50d6d78bef464c47 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 27 Feb 2015 14:31:27 +0000 Subject: [PATCH 49/83] Add debug output when a plugin is loaded --- src/Composer/Plugin/PluginManager.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 96b743de1..6bf5d4cf5 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -79,6 +79,9 @@ class PluginManager */ public function addPlugin(PluginInterface $plugin) { + if ($this->io->isDebug()) { + $this->io->writeError('Loading plugin '.get_class($plugin)); + } $this->plugins[] = $plugin; $plugin->activate($this->composer, $this->io); From d5feea83b6b454a30e41d9b3963620bce03bad4b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 28 Feb 2015 20:20:22 +0000 Subject: [PATCH 50/83] Sync up diagnose command with the installer --- src/Composer/Command/DiagnoseCommand.php | 100 +++++++++++++++++++---- 1 file changed, 85 insertions(+), 15 deletions(-) diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index d6c6ec968..423213741 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -343,10 +343,34 @@ EOT } $iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.'; + if (!function_exists('json_decode')) { + $errors['json'] = true; + } + + if (!extension_loaded('Phar')) { + $errors['phar'] = true; + } + + if (!extension_loaded('filter')) { + $errors['filter'] = true; + } + + if (!extension_loaded('hash')) { + $errors['hash'] = true; + } + + if (!extension_loaded('ctype')) { + $errors['ctype'] = true; + } + if (!ini_get('allow_url_fopen')) { $errors['allow_url_fopen'] = true; } + if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) { + $errors['ioncube'] = ioncube_loader_version(); + } + if (version_compare(PHP_VERSION, '5.3.2', '<')) { $errors['php'] = PHP_VERSION; } @@ -356,19 +380,13 @@ EOT } if (!extension_loaded('openssl')) { - $warnings['openssl'] = true; + $errors['openssl'] = true; } if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) { $warnings['apc_cli'] = true; } - if (ini_get('xdebug.profiler_enabled')) { - $warnings['xdebug_profile'] = true; - } elseif (extension_loaded('xdebug')) { - $warnings['xdebug_loaded'] = true; - } - ob_start(); phpinfo(INFO_GENERAL); $phpinfo = ob_get_clean(); @@ -384,19 +402,76 @@ EOT } } + if (ini_get('xdebug.profiler_enabled')) { + $warnings['xdebug_profile'] = true; + } elseif (extension_loaded('xdebug')) { + $warnings['xdebug_loaded'] = true; + } + if (!empty($errors)) { foreach ($errors as $error => $current) { switch ($error) { + case 'json': + $text = PHP_EOL."The json extension is missing.".PHP_EOL; + $text .= "Install it or recompile php without --disable-json"; + break; + + case 'phar': + $text = PHP_EOL."The phar extension is missing.".PHP_EOL; + $text .= "Install it or recompile php without --disable-phar"; + break; + + case 'filter': + $text = PHP_EOL."The filter extension is missing.".PHP_EOL; + $text .= "Install it or recompile php without --disable-filter"; + break; + + case 'hash': + $text = PHP_EOL."The hash extension is missing.".PHP_EOL; + $text .= "Install it or recompile php without --disable-hash"; + break; + + case 'ctype': + $text = PHP_EOL."The ctype extension is missing.".PHP_EOL; + $text .= "Install it or recompile php without --disable-ctype"; + break; + + case 'unicode': + $text = PHP_EOL."The detect_unicode setting must be disabled.".PHP_EOL; + $text .= "Add the following to the end of your `php.ini`:".PHP_EOL; + $text .= " detect_unicode = Off"; + $displayIniMessage = true; + break; + + case 'suhosin': + $text = PHP_EOL."The suhosin.executor.include.whitelist setting is incorrect.".PHP_EOL; + $text .= "Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):".PHP_EOL; + $text .= " suhosin.executor.include.whitelist = phar ".$current; + $displayIniMessage = true; + break; + case 'php': - $text = "Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher."; + $text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher."; break; case 'allow_url_fopen': - $text = "The allow_url_fopen setting is incorrect.".PHP_EOL; + $text = PHP_EOL."The allow_url_fopen setting is incorrect.".PHP_EOL; $text .= "Add the following to the end of your `php.ini`:".PHP_EOL; - $text .= " allow_url_fopen = On"; + $text .= " allow_url_fopen = On"; $displayIniMessage = true; break; + + case 'ioncube': + $text = PHP_EOL."Your ionCube Loader extension ($current) is incompatible with Phar files.".PHP_EOL; + $text .= "Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:".PHP_EOL; + $text .= " zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so"; + $displayIniMessage = true; + break; + + case 'openssl': + $text = PHP_EOL."The openssl extension is missing, which means that secure HTTPS transfers are impossible.".PHP_EOL; + $text .= "If possible you should enable it or recompile php with --with-openssl"; + break; } $out($text, 'error'); } @@ -425,11 +500,6 @@ EOT $text .= " Recompile it without this flag if possible"; break; - case 'openssl': - $text = "The openssl extension is missing, which will reduce the security and stability of Composer.".PHP_EOL; - $text .= " If possible you should enable it or recompile php with --with-openssl"; - break; - case 'php': $text = "Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL; $text .= " Composer works with 5.3.2+ for most people, but there might be edge case issues."; From 05e196893b1225898de280ef8f97d5f2be684e8f Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Sat, 28 Feb 2015 12:59:43 -0800 Subject: [PATCH 51/83] Add --no-check-publish option to "composer validate" This is useful when you want to use composer to manage dependencies, but don't actually want your project to be installable as a composer package. Any issues that would prevent publishing are still shown, but as a warning instead of an error. --- src/Composer/Command/ValidateCommand.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php index 08aaef209..9298e4175 100644 --- a/src/Composer/Command/ValidateCommand.php +++ b/src/Composer/Command/ValidateCommand.php @@ -37,6 +37,7 @@ class ValidateCommand extends Command ->setDescription('Validates a composer.json') ->setDefinition(array( new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not make a complete validation'), + new InputOption('no-check-publish', null, InputOption::VALUE_NONE, 'Do not check for publish errors'), new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json') )) ->setHelp(<<getIO()); $checkAll = $input->getOption('no-check-all') ? 0 : ValidatingArrayLoader::CHECK_ALL; + $checkPublish = !$input->getOption('no-check-publish'); list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll); // output errors/warnings @@ -86,16 +88,23 @@ EOT } $messages = array( - 'error' => array_merge($errors, $publishErrors), + 'error' => $errors, 'warning' => $warnings, ); + // If checking publish errors, display them errors, otherwise just show them as warnings + if ($checkPublish) { + $messages['error'] = array_merge($messages['error'], $publishErrors); + } else { + $messages['warning'] = array_merge($messages['warning'], $publishErrors); + } + foreach ($messages as $style => $msgs) { foreach ($msgs as $msg) { $this->getIO()->writeError('<' . $style . '>' . $msg . ''); } } - return $errors || $publishErrors ? 1 : 0; + return $errors || ($publishErrors && $checkPublish) ? 1 : 0; } } From fe2b2e651aafb22e6a3fa20adb04467a72e7fd4e Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Sun, 1 Mar 2015 20:47:15 +0000 Subject: [PATCH 52/83] Added php7 to travis --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4aed11625..c3dabf51f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,14 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm +matrix: + fast_finish: true + allow_failures: + - php: 7.0 + before_script: - sudo apt-get install parallel - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini From b098a2fdde42a2bdbf0926a3af616cdef4ad3829 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 2 Mar 2015 16:40:05 +0000 Subject: [PATCH 53/83] Fix clear cache when a dir does not exist, fixes #3810 --- src/Composer/Command/ClearCacheCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Composer/Command/ClearCacheCommand.php b/src/Composer/Command/ClearCacheCommand.php index 9512ba416..818b8ee30 100644 --- a/src/Composer/Command/ClearCacheCommand.php +++ b/src/Composer/Command/ClearCacheCommand.php @@ -53,13 +53,13 @@ EOT if (!$cachePath) { $io->writeError("Cache directory does not exist ($key): $cachePath"); - return; + continue; } $cache = new Cache($io, $cachePath); if (!$cache->isEnabled()) { $io->writeError("Cache is not enabled ($key): $cachePath"); - return; + continue; } $io->writeError("Clearing cache ($key): $cachePath"); From 82b7fdf4c19b956a1a5b47337db1bb083f698ccf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 2 Mar 2015 17:02:20 +0000 Subject: [PATCH 54/83] Add BC for Script\Event instances, fixes #3811 --- src/Composer/EventDispatcher/EventDispatcher.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 2fa837615..bbebfae31 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -236,6 +236,12 @@ class EventDispatcher $event->getOperations(), $event->getOperation() ); } + if (!$event instanceof $expected && $expected === 'Composer\Script\Event') { + $event = new \Composer\Script\Event( + $event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), + $event->getArguments(), $event->getFlags() + ); + } return $event; } From eadc167b121359986f542cc9cf976ecee3fcbf69 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 2 Mar 2015 18:20:22 +0000 Subject: [PATCH 55/83] Fix BC layer for events --- src/Composer/EventDispatcher/EventDispatcher.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index bbebfae31..3bb1c8496 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -205,10 +205,6 @@ class EventDispatcher */ protected function checkListenerExpectedEvent($target, Event $event) { - if (!$event instanceof Script\Event) { - return $event; - } - try { $reflected = new \ReflectionParameter($target, 0); } catch (\Exception $e) { From be22a87d9cf64895e96ea12b3aee89c1d282e520 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 3 Mar 2015 11:46:55 +0100 Subject: [PATCH 56/83] Run processes with predictable LANGUAGE=C --- src/Composer/Util/ProcessExecutor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 38f5bba00..60e48a9b9 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -56,7 +56,7 @@ class ProcessExecutor $this->captureOutput = count(func_get_args()) > 1; $this->errorOutput = null; - $process = new Process($command, $cwd, null, null, static::getTimeout()); + $process = new Process($command, $cwd, array('LANGUAGE' => 'C') + $_ENV + $_SERVER, null, static::getTimeout()); $callback = is_callable($output) ? $output : array($this, 'outputHandler'); $process->run($callback); From f35d6ac0e0f483a3398444bfe4b11ecb3c082567 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Tue, 3 Mar 2015 12:26:47 +0000 Subject: [PATCH 57/83] Removed php7 to travis allowed_failures --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3dabf51f..51fe9679f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,6 @@ php: - 7.0 - hhvm -matrix: - fast_finish: true - allow_failures: - - php: 7.0 - before_script: - sudo apt-get install parallel - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini From a02f3e79b84f00d350c9ac825bbcd21746c7d26c Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 4 Mar 2015 16:48:39 +0100 Subject: [PATCH 58/83] Switch to the docker-based infrastructure on Travis --- .travis.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51fe9679f..3e9443e80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,15 @@ language: php +sudo: false + +cache: + directories: + - $HOME/.composer/cache + +addons: + apt_packages: + - parallel + php: - 5.3.3 - 5.3 @@ -10,10 +20,9 @@ php: - hhvm before_script: - - sudo apt-get install parallel - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini - - composer install --prefer-source - - bin/composer install --prefer-source + - composer install + - bin/composer install - git config --global user.name travis-ci - git config --global user.email travis@example.com From 26799f4244a14050ec015323af9fa83b0a66436d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 4 Mar 2015 23:50:10 +0000 Subject: [PATCH 59/83] Update script/plugin docs --- doc/articles/plugins.md | 13 ++------- doc/articles/scripts.md | 60 ++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/doc/articles/plugins.md b/doc/articles/plugins.md index 65884fd18..9da3badad 100644 --- a/doc/articles/plugins.md +++ b/doc/articles/plugins.md @@ -82,15 +82,7 @@ Furthermore plugins may implement the event handlers automatically registered with the `EventDispatcher` when the plugin is loaded. -The events available for plugins are: - -* **COMMAND**, is called at the beginning of all commands that load plugins. - It provides you with access to the input and output objects of the program. -* **PRE_FILE_DOWNLOAD**, is triggered before files are downloaded and allows - you to manipulate the `RemoteFilesystem` object prior to downloading files - based on the URL to be downloaded. - -> A plugin can also subscribe to [script events][7]. +Plugin can subscribe to any of the available [script events](scripts.md#event-names). Example: @@ -148,7 +140,7 @@ list of installed packages. Additionally all plugin packages installed in the local project plugins are loaded. > You may pass the `--no-plugins` option to composer commands to disable all -> installed commands. This may be particularly helpful if any of the plugins +> installed plugins. This may be particularly helpful if any of the plugins > causes errors and you wish to update or uninstall it. [1]: ../04-schema.md#type @@ -157,4 +149,3 @@ local project plugins are loaded. [4]: https://github.com/composer/composer/blob/master/src/Composer/Composer.php [5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php [6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php -[7]: ./scripts.md#event-names diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 3e6ef54cf..dec1fa06d 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -20,20 +20,16 @@ the Composer execution process. Composer fires the following named events during its execution process: +### Command Events + - **pre-install-cmd**: occurs before the `install` command is executed. - **post-install-cmd**: occurs after the `install` command is executed. - **pre-update-cmd**: occurs before the `update` command is executed. - **post-update-cmd**: occurs after the `update` command is executed. - **pre-status-cmd**: occurs before the `status` command is executed. - **post-status-cmd**: occurs after the `status` command is executed. -- **pre-dependencies-solving**: occurs before the dependencies are resolved. -- **post-dependencies-solving**: occurs after the dependencies are resolved. -- **pre-package-install**: occurs before a package is installed. -- **post-package-install**: occurs after a package is installed. -- **pre-package-update**: occurs before a package is updated. -- **post-package-update**: occurs after a package is updated. -- **pre-package-uninstall**: occurs before a package has been uninstalled. -- **post-package-uninstall**: occurs after a package has been uninstalled. +- **pre-archive-cmd**: occurs before the `archive` command is executed. +- **post-archive-cmd**: occurs after the `archive` command is executed. - **pre-autoload-dump**: occurs before the autoloader is dumped, either during `install`/`update`, or via the `dump-autoload` command. - **post-autoload-dump**: occurs after the autoloader is dumped, either @@ -42,8 +38,28 @@ Composer fires the following named events during its execution process: installed, during the `create-project` command. - **post-create-project-cmd**: occurs after the `create-project` command is executed. -- **pre-archive-cmd**: occurs before the `archive` command is executed. -- **post-archive-cmd**: occurs after the `archive` command is executed. + +### Installer Events + +- **pre-dependencies-solving**: occurs before the dependencies are resolved. +- **post-dependencies-solving**: occurs after the dependencies are resolved. + +### Package Events + +- **pre-package-install**: occurs before a package is installed. +- **post-package-install**: occurs after a package is installed. +- **pre-package-update**: occurs before a package is updated. +- **post-package-update**: occurs after a package is updated. +- **pre-package-uninstall**: occurs before a package has been uninstalled. +- **post-package-uninstall**: occurs after a package has been uninstalled. + +### Plugin Events + +- **command**: occurs before any Composer Command is executed on the CLI. It + provides you with access to the input and output objects of the program. +- **pre-file-download**: occurs before files are downloaded and allows + you to manipulate the `RemoteFilesystem` object prior to downloading files + based on the URL to be downloaded. > **Note:** Composer makes no assumptions about the state of your dependencies > prior to `install` or `update`. Therefore, you should not specify scripts @@ -96,6 +112,7 @@ that might be used to execute the PHP callbacks: namespace MyVendor; use Composer\Script\Event; +use Composer\Installer\PackageEvent; class MyClass { @@ -105,7 +122,7 @@ class MyClass // do stuff } - public static function postPackageInstall(Event $event) + public static function postPackageInstall(PackageEvent $event) { $installedPackage = $event->getOperation()->getPackage(); // do stuff @@ -118,14 +135,21 @@ class MyClass } ``` -When an event is fired, Composer's internal event handler receives a -`Composer\Script\Event` object, which is passed as the first argument to your -PHP callback. This `Event` object has getters for other contextual objects: +When an event is fired, your PHP callback receives as first argument an +`Composer\EventDispatcher\Event` object. This object has a `getName()` method +that lets you retrieve event name. -- `getComposer()`: returns the current instance of `Composer\Composer` -- `getName()`: returns the name of the event being fired as a string -- `getIO()`: returns the current input/output stream which implements -`Composer\IO\IOInterface` for writing to the console +Depending on the script types (see list above) you will get various event +subclasses containing various getters with relevant data and associated +objects: + +- Base class: [`Composer\EventDispatcher\Event`](https://getcomposer.org/apidoc/master/Composer/EventDispatcher/Event.html) +- Command Events: [`Composer\Script\Event`](https://getcomposer.org/apidoc/master/Composer/Script/Event.html) +- Installer Events: [`Composer\Installer\InstallerEvent`](https://getcomposer.org/apidoc/master/Composer/Installer/InstallerEvent.html) +- Package Events: [`Composer\Installer\PackageEvent`](https://getcomposer.org/apidoc/master/Composer/Installer/PackageEvent.html) +- Plugin Events: + - command: [`Composer\Plugin\CommandEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/CommandEvent.html) + - pre-file-download: [`Composer\Plugin\PreFileDownloadEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/PreFileDownloadEvent.html) ## Running scripts manually From ef0191ee6a3ec43c73511bb3840349763e208049 Mon Sep 17 00:00:00 2001 From: Hello Date: Thu, 5 Mar 2015 16:27:27 +0300 Subject: [PATCH 60/83] Duplicate download progress --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 9e6b50d74..4d7acf14e 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -327,7 +327,7 @@ class RemoteFilesystem $progression = round($bytesTransferred / $this->bytesMax * 100); } - if ((0 === $progression % 5) && $progression !== $this->lastProgress) { + if ((0 === $progression % 5) && 100 !== $progression && $progression !== $this->lastProgress) { $this->lastProgress = $progression; $this->io->overwriteError(" Downloading: $progression%", false); } From 8e6f62e76923c0936cbde64e359cabca1bfa23bb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Mar 2015 14:16:44 +0000 Subject: [PATCH 61/83] Bump max memory to 1GB, fixes #3785 --- bin/composer | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/composer b/bin/composer index 3a1b5df02..401efb5b0 100755 --- a/bin/composer +++ b/bin/composer @@ -32,9 +32,9 @@ if (function_exists('ini_set')) { }; $memoryLimit = trim(ini_get('memory_limit')); - // Increase memory_limit if it is lower than 512M - if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 512 * 1024 * 1024) { - @ini_set('memory_limit', '512M'); + // Increase memory_limit if it is lower than 1GB + if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 1024 * 1024 * 1024) { + @ini_set('memory_limit', '1G'); } unset($memoryInBytes, $memoryLimit); } From d9b5c884ba9fd6d8be111894c55bb7811dbe9b73 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Mar 2015 14:24:43 +0000 Subject: [PATCH 62/83] Detect and warn JSON encoding failures, refs #3786 --- src/Composer/Json/JsonFile.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index 3375329c7..7fbc42392 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -184,6 +184,9 @@ class JsonFile { if (version_compare(PHP_VERSION, '5.4', '>=')) { $json = json_encode($data, $options); + if (false === $json) { + self::throwEncodeError(json_last_error()); + } // compact brackets to follow recent php versions if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) { @@ -195,6 +198,9 @@ class JsonFile } $json = json_encode($data); + if (false === $json) { + self::throwEncodeError(json_last_error()); + } $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT); $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE); @@ -209,6 +215,28 @@ class JsonFile return $result; } + private static function throwEncodeError($code) + { + switch ($code) { + case JSON_ERROR_DEPTH: + $msg = 'Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $msg = 'Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + $msg = 'Unexpected control character found'; + break; + case JSON_ERROR_UTF8: + $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + $msg = 'Unknown error'; + } + + throw new \RuntimeException('JSON encoding failed: '.$msg); + } + /** * Parses json string and returns hash. * From ad40cdc3feff067b0947a1a66112c910c196ce33 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Mar 2015 14:40:29 +0000 Subject: [PATCH 63/83] Fix overwriteError behavior, fixes #3817 --- src/Composer/IO/ConsoleIO.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index 0ab617a94..7de4d8ede 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -197,7 +197,12 @@ class ConsoleIO extends BaseIO if ($newline) { $this->doWrite('', true, $stderr); } - $this->lastMessage = $messages; + + if ($stderr) { + $this->lastMessageErr = $messages; + } else { + $this->lastMessage = $messages; + } } /** From 331425bcb3cd13a5d5d807c13c6a651229b56ac8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Mar 2015 14:44:15 +0000 Subject: [PATCH 64/83] Fix output of first line of progress when output is not decorated, refs #3818 --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 9e6b50d74..35355de6a 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -158,7 +158,7 @@ class RemoteFilesystem $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { - $this->io->writeError(" Downloading: connection...", false); + $this->io->writeError(" Downloading: connection...", !$this->io->isDecorated()); } $errorMessage = ''; From 1bb871dca837485e4d8d6e710066265386c90e75 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Thu, 5 Mar 2015 22:01:09 +0000 Subject: [PATCH 65/83] Add docBlock and fix CS --- src/Composer/Json/JsonFile.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index 7fbc42392..b514e5b43 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -215,21 +215,27 @@ class JsonFile return $result; } + /** + * Throws an exception according to a given code with a customized message + * + * @param int $code return code of json_last_error function + * @throws \RuntimeException + */ private static function throwEncodeError($code) { switch ($code) { case JSON_ERROR_DEPTH: $msg = 'Maximum stack depth exceeded'; - break; + break; case JSON_ERROR_STATE_MISMATCH: $msg = 'Underflow or the modes mismatch'; - break; + break; case JSON_ERROR_CTRL_CHAR: $msg = 'Unexpected control character found'; - break; + break; case JSON_ERROR_UTF8: $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; + break; default: $msg = 'Unknown error'; } From 4f57fafb8d633b328a203481a581c2e0762ba3ea Mon Sep 17 00:00:00 2001 From: Francis Besset Date: Fri, 6 Mar 2015 14:09:50 +0100 Subject: [PATCH 66/83] [create-project] Used no progress value for dependencies --- src/Composer/Command/CreateProjectCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index e7186fec8..f5d87d303 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -145,6 +145,8 @@ EOT } $composer = Factory::create($io, null, $disablePlugins); + $composer->getDownloadManager()->setOutputProgress(!$noProgress); + $fs = new Filesystem(); if ($noScripts === false) { From b80038804ff791a9d4608d737ad937b6033b0bae Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 6 Mar 2015 16:20:27 +0000 Subject: [PATCH 67/83] Fix env override regression, fixes #3820 --- src/Composer/Command/CreateProjectCommand.php | 3 ++- src/Composer/Command/RunScriptCommand.php | 3 ++- src/Composer/Command/ScriptAliasCommand.php | 3 ++- src/Composer/Util/Git.php | 4 ++++ src/Composer/Util/ProcessExecutor.php | 2 +- src/Composer/Util/Svn.php | 1 + tests/Composer/Test/AllFunctionalTest.php | 6 ++++-- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index f5d87d303..65366dfe2 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -316,7 +316,8 @@ EOT $io->writeError('Created project in ' . $directory . ''); chdir($directory); - putenv('COMPOSER_ROOT_VERSION='.$package->getPrettyVersion()); + $_SERVER['COMPOSER_ROOT_VERSION'] = $package->getPrettyVersion(); + putenv('COMPOSER_ROOT_VERSION='.$_SERVER['COMPOSER_ROOT_VERSION']); return $installedFromVcs; } diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index 979f86a02..8b5b13d2a 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -87,7 +87,8 @@ EOT // add the bin dir to the PATH to make local binaries of deps usable in scripts $binDir = $composer->getConfig()->get('bin-dir'); if (is_dir($binDir)) { - putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH')); + $_SERVER['PATH'] = realpath($binDir).PATH_SEPARATOR.getenv('PATH'); + putenv('PATH='.$_SERVER['PATH']); } $args = $input->getArgument('args'); diff --git a/src/Composer/Command/ScriptAliasCommand.php b/src/Composer/Command/ScriptAliasCommand.php index 958678068..b8f0abff5 100644 --- a/src/Composer/Command/ScriptAliasCommand.php +++ b/src/Composer/Command/ScriptAliasCommand.php @@ -57,7 +57,8 @@ EOT // add the bin dir to the PATH to make local binaries of deps usable in scripts $binDir = $composer->getConfig()->get('bin-dir'); if (is_dir($binDir)) { - putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH')); + $_SERVER['PATH'] = realpath($binDir).PATH_SEPARATOR.getenv('PATH'); + putenv('PATH='.$_SERVER['PATH']); } $args = $input->getArguments(); diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index e965384e7..34b686d9a 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -164,18 +164,22 @@ class Git // added in git 1.7.1, prevents prompting the user for username/password if (getenv('GIT_ASKPASS') !== 'echo') { putenv('GIT_ASKPASS=echo'); + unset($_SERVER['GIT_ASKPASS']); } // clean up rogue git env vars in case this is running in a git hook if (getenv('GIT_DIR')) { putenv('GIT_DIR'); + unset($_SERVER['GIT_DIR']); } if (getenv('GIT_WORK_TREE')) { putenv('GIT_WORK_TREE'); + unset($_SERVER['GIT_WORK_TREE']); } // clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940 putenv("DYLD_LIBRARY_PATH"); + unset($_SERVER['DYLD_LIBRARY_PATH']); } public static function getGitHubDomainsRegex(Config $config) diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 60e48a9b9..e7cfa3dcc 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -56,7 +56,7 @@ class ProcessExecutor $this->captureOutput = count(func_get_args()) > 1; $this->errorOutput = null; - $process = new Process($command, $cwd, array('LANGUAGE' => 'C') + $_ENV + $_SERVER, null, static::getTimeout()); + $process = new Process($command, $cwd, array_replace($_ENV, $_SERVER, array('LANGUAGE' => 'C')), null, static::getTimeout()); $callback = is_callable($output) ? $output : array($this, 'outputHandler'); $process->run($callback); diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index af7dc6cbd..9ba08bf85 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -81,6 +81,7 @@ class Svn { // clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940 putenv("DYLD_LIBRARY_PATH"); + unset($_SERVER['DYLD_LIBRARY_PATH']); } /** diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index 6670cc4fa..1b720ad29 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -42,7 +42,8 @@ class AllFunctionalTest extends \PHPUnit_Framework_TestCase } if ($this->oldenv) { $fs->removeDirectory(getenv('COMPOSER_HOME')); - putenv('COMPOSER_HOME='.$this->oldenv); + $_SERVER['COMPOSER_HOME'] = $this->oldenv; + putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']); $this->oldenv = null; } } @@ -86,7 +87,8 @@ class AllFunctionalTest extends \PHPUnit_Framework_TestCase $testData = $this->parseTestFile($testFile); $this->oldenv = getenv('COMPOSER_HOME'); - putenv('COMPOSER_HOME='.$this->testDir.'home'); + $_SERVER['COMPOSER_HOME'] = $this->testDir.'home'; + putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']); $cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN']; $proc = new Process($cmd, __DIR__.'/Fixtures/functional', null, null, 300); From c41a187b62791b1f290c37ad0f86a159c00f5961 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Sat, 7 Mar 2015 13:00:21 +0000 Subject: [PATCH 68/83] Use get home from Config instead of factory --- src/Composer/Factory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index da0a9ef63..504ae8815 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -113,7 +113,7 @@ class Factory $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir))); // load global config - $file = new JsonFile($home.'/config.json'); + $file = new JsonFile($config->get('home').'/config.json'); if ($file->exists()) { if ($io && $io->isDebug()) { $io->writeError('Loading config file ' . $file->getPath()); From e79d067690c4dd833416e790e497431cd549dce4 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Sat, 7 Mar 2015 19:01:54 +0000 Subject: [PATCH 69/83] Make parseJson safer --- src/Composer/Json/JsonFile.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index b514e5b43..cf9dea5f4 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -253,6 +253,9 @@ class JsonFile */ public static function parseJson($json, $file = null) { + if (null === $json) { + return; + } $data = json_decode($json, true); if (null === $data && JSON_ERROR_NONE !== json_last_error()) { self::validateSyntax($json, $file); From 3667e18885461459ef0072e7a2298d3060946459 Mon Sep 17 00:00:00 2001 From: Haralan Dobrev Date: Sun, 8 Mar 2015 19:30:56 +0200 Subject: [PATCH 70/83] Test on HHVM nightly releases. Allow to fail. Nightly releases could change in unpredictable way. So they should not fail the whole build. However we could catch problems and breaking changes on next versions of HHVM early. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3e9443e80..a2929f562 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,11 @@ php: - 5.6 - 7.0 - hhvm + - hhvm-nightly + +matrix: + allow_failures: + - php: hhvm-nightly before_script: - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini From 8168f69ae7a1c4cbebc3b2b023591c24c3529add Mon Sep 17 00:00:00 2001 From: Haralan Dobrev Date: Mon, 9 Mar 2015 10:22:39 +0200 Subject: [PATCH 71/83] Report Travis CI build success early This will report the build has succceeded even if allowed to fail jobs are still running. See https://github.com/composer/composer/pull/3828. Docs: http://docs.travis-ci.com/user/build-configuration/#Fast-finishing Props to @fonsecas72. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a2929f562..818224376 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ php: - hhvm-nightly matrix: + fast_finish: true allow_failures: - php: hhvm-nightly From b296e654eb3e136ca6fa08fa3bcb1d4782c13f8b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 9 Mar 2015 11:12:32 +0000 Subject: [PATCH 72/83] Re-use existing autoloader suffix if available, fixes #3701 --- src/Composer/Autoload/AutoloadGenerator.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 3326861c1..3e78494a6 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -214,7 +214,16 @@ EOF; $classmapFile .= ");\n"; if (!$suffix) { - $suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true)); + if (is_readable($vendorPath.'/autoload.php')) { + $content = file_get_contents($vendorPath.'/autoload.php'); + if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) { + $suffix = $match[1]; + } + } + + if (!$suffix) { + $suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true)); + } } file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile); From 33ea86573e0bc3c60fc13dfdb4812a060811086d Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Mon, 9 Mar 2015 09:37:56 -0700 Subject: [PATCH 73/83] Add support for using classmap to autoload Hack enums fixes composer/composer#3823 Ran tests with both PHP5.5.9-1ubuntu4.5 and HHVM 3.6. Test fails on HHVM only if I back out the ClassMapGenerator.php change. --- src/Composer/Autoload/ClassMapGenerator.php | 14 ++++++++++++-- .../Test/Autoload/ClassMapGeneratorTest.php | 6 ++++++ .../Test/Autoload/Fixtures/hhvm3.3/HackEnum.php | 6 ++++++ .../Fixtures/hhvm3.3/NamespacedHackEnum.php | 7 +++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/Composer/Test/Autoload/Fixtures/hhvm3.3/HackEnum.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/hhvm3.3/NamespacedHackEnum.php diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index f8f18fc28..48b6bdfda 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -113,6 +113,10 @@ class ClassMapGenerator private static function findClasses($path) { $traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait'; + $enums = ''; + if (defined('HPHP_VERSION') && version_compare(HPHP_VERSION, '3.3', '>=')) { + $enums = '|enum'; + } try { $contents = @php_strip_whitespace($path); @@ -129,7 +133,7 @@ class ClassMapGenerator } // return early if there is no chance of matching anything in this file - if (!preg_match('{\b(?:class|interface'.$traits.')\s}i', $contents)) { + if (!preg_match('{\b(?:class|interface'.$traits.$enums.')\s}i', $contents)) { return array(); } @@ -154,7 +158,7 @@ class ClassMapGenerator preg_match_all('{ (?: - \b(?])(?Pclass|interface'.$traits.') \s+ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*) + \b(?])(?Pclass|interface'.$traits.$enums.') \s+ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*) | \b(?])(?Pnamespace) (?P\s+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*\\\\\s*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)? \s*[\{;] ) }ix', $contents, $matches); @@ -170,6 +174,12 @@ class ClassMapGenerator if ($name[0] === ':') { // This is an XHP class, https://github.com/facebook/xhp $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1); + } else if ($matches['type'][$i] === 'enum') { + // In Hack, something like: + // enum Foo: int { HERP = '123'; } + // The regex above captures the colon, which isn't part of + // the class name. + $name = rtrim($name, ':'); } $classes[] = ltrim($namespace . $name, '\\'); } diff --git a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php index 81f99e57b..beaeba420 100644 --- a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php +++ b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php @@ -74,6 +74,12 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase 'Foo\\CBar' => __DIR__.'/Fixtures/php5.4/traits.php', )); } + if (defined('HPHP_VERSION') && version_compare(HPHP_VERSION, '3.3', '>=')) { + $data[] = array(__DIR__.'/Fixtures/hhvm3.3', array( + 'FooEnum' => __DIR__.'/Fixtures/hhvm3.3/HackEnum.php', + 'Foo\BarEnum' => __DIR__.'/Fixtures/hhvm3.3/NamespacedHackEnum.php', + )); + } return $data; } diff --git a/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/HackEnum.php b/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/HackEnum.php new file mode 100644 index 000000000..4b8dbfd40 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/HackEnum.php @@ -0,0 +1,6 @@ + Date: Mon, 9 Mar 2015 10:02:10 -0700 Subject: [PATCH 74/83] Use HHVM_VERSION instead of HPHP_VERSION --- src/Composer/Autoload/ClassMapGenerator.php | 2 +- tests/Composer/Test/Autoload/ClassMapGeneratorTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 48b6bdfda..5134be80f 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -114,7 +114,7 @@ class ClassMapGenerator { $traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait'; $enums = ''; - if (defined('HPHP_VERSION') && version_compare(HPHP_VERSION, '3.3', '>=')) { + if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { $enums = '|enum'; } diff --git a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php index beaeba420..3f9e18884 100644 --- a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php +++ b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php @@ -74,7 +74,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase 'Foo\\CBar' => __DIR__.'/Fixtures/php5.4/traits.php', )); } - if (defined('HPHP_VERSION') && version_compare(HPHP_VERSION, '3.3', '>=')) { + if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { $data[] = array(__DIR__.'/Fixtures/hhvm3.3', array( 'FooEnum' => __DIR__.'/Fixtures/hhvm3.3/HackEnum.php', 'Foo\BarEnum' => __DIR__.'/Fixtures/hhvm3.3/NamespacedHackEnum.php', From bdf51ab16dd5b05e30eb578ab15daf86284b24ff Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Mon, 9 Mar 2015 10:05:12 -0700 Subject: [PATCH 75/83] Single variable for traits and enums --- src/Composer/Autoload/ClassMapGenerator.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 5134be80f..862e44ba2 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -112,10 +112,9 @@ class ClassMapGenerator */ private static function findClasses($path) { - $traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait'; - $enums = ''; + $extraTypes = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait'; if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { - $enums = '|enum'; + $extraTypes .= '|enum'; } try { @@ -133,7 +132,7 @@ class ClassMapGenerator } // return early if there is no chance of matching anything in this file - if (!preg_match('{\b(?:class|interface'.$traits.$enums.')\s}i', $contents)) { + if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) { return array(); } @@ -158,7 +157,7 @@ class ClassMapGenerator preg_match_all('{ (?: - \b(?])(?Pclass|interface'.$traits.$enums.') \s+ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*) + \b(?])(?Pclass|interface'.$extraTypes.') \s+ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*) | \b(?])(?Pnamespace) (?P\s+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*\\\\\s*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)? \s*[\{;] ) }ix', $contents, $matches); From 23d5e30fbcf7c660f6a4be36e4470d105bf36536 Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Mon, 9 Mar 2015 11:28:44 -0700 Subject: [PATCH 76/83] Add test for Generics class Already worked, just adding a test. --- tests/Composer/Test/Autoload/ClassMapGeneratorTest.php | 1 + tests/Composer/Test/Autoload/Fixtures/hhvm3.3/Generics.php | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 tests/Composer/Test/Autoload/Fixtures/hhvm3.3/Generics.php diff --git a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php index 3f9e18884..b8efc0c80 100644 --- a/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php +++ b/tests/Composer/Test/Autoload/ClassMapGeneratorTest.php @@ -78,6 +78,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase $data[] = array(__DIR__.'/Fixtures/hhvm3.3', array( 'FooEnum' => __DIR__.'/Fixtures/hhvm3.3/HackEnum.php', 'Foo\BarEnum' => __DIR__.'/Fixtures/hhvm3.3/NamespacedHackEnum.php', + 'GenericsClass' => __DIR__.'/Fixtures/hhvm3.3/Generics.php', )); } diff --git a/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/Generics.php b/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/Generics.php new file mode 100644 index 000000000..e5d1aa12a --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/hhvm3.3/Generics.php @@ -0,0 +1,4 @@ + { +} From c87418099c829353ad706f2780ef90d3d7a0b4e1 Mon Sep 17 00:00:00 2001 From: Sergey Gonimar Date: Fri, 13 Mar 2015 14:25:55 +0500 Subject: [PATCH 77/83] Fix docs basic-auth => http-basic --- doc/articles/http-basic-authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/articles/http-basic-authentication.md b/doc/articles/http-basic-authentication.md index 1add2d7a6..2119513ce 100644 --- a/doc/articles/http-basic-authentication.md +++ b/doc/articles/http-basic-authentication.md @@ -40,7 +40,7 @@ username/password pairs, for example: ```json { - "basic-auth": { + "http-basic": { "repo.example1.org": { "username": "my-username1", "password": "my-secret-password1" From 6c35dd6b2da1acb1e593482be294880e4d747388 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Mon, 23 Mar 2015 19:36:16 +0100 Subject: [PATCH 78/83] Improved wording All other verbs use are in the form of "doing something", ie Installing, Downloading. "connection" is the odd one out. --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index ce22ec136..4aeae4e05 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -158,7 +158,7 @@ class RemoteFilesystem $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { - $this->io->writeError(" Downloading: connection...", !$this->io->isDecorated()); + $this->io->writeError(" Downloading: Connecting...", !$this->io->isDecorated()); } $errorMessage = ''; From 54d61ec486bf70f22cc3cf490afcd63535283c74 Mon Sep 17 00:00:00 2001 From: Peter Cowburn Date: Mon, 23 Mar 2015 20:49:40 +0000 Subject: [PATCH 79/83] Use justinrainbow/json-schema 1.4 justinrainbow/json-schema version 1.4.0 has been tagged (https://github.com/justinrainbow/json-schema/releases/tag/1.4.0), which fixes naming conflicts with Scalar Type Hints in (what will be) PHP 7. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8cdf0fd9c..f3eee609a 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require": { "php": ">=5.3.2", - "justinrainbow/json-schema": "~1.3", + "justinrainbow/json-schema": "~1.4", "seld/jsonlint": "~1.0", "symfony/console": "~2.5", "symfony/finder": "~2.2", From ddd6ea1c2f90950f3b58ade3593756f397307af0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Mar 2015 00:12:43 +0000 Subject: [PATCH 80/83] Update deps --- composer.lock | 62 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/composer.lock b/composer.lock index 0310c6c0b..b0ae61425 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "0aebec3992608f24110593481334c989", + "hash": "8317ca3b690ea80633fe3fb2b0d440cb", "packages": [ { "name": "justinrainbow/json-schema", - "version": "1.3.7", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "87b54b460febed69726c781ab67462084e97a105" + "reference": "680d026082c3aa234b2d8617c50e9c73999913ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/87b54b460febed69726c781ab67462084e97a105", - "reference": "87b54b460febed69726c781ab67462084e97a105", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/680d026082c3aa234b2d8617c50e9c73999913ba", + "reference": "680d026082c3aa234b2d8617c50e9c73999913ba", "shasum": "" }, "require": { @@ -70,7 +70,7 @@ "json", "schema" ], - "time": "2014-08-25 02:48:14" + "time": "2015-03-23 20:38:38" }, { "name": "seld/jsonlint", @@ -120,17 +120,17 @@ }, { "name": "symfony/console", - "version": "v2.6.4", + "version": "v2.6.5", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" + "reference": "53f86497ccd01677e22435cfb7262599450a90d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", - "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "url": "https://api.github.com/repos/symfony/Console/zipball/53f86497ccd01677e22435cfb7262599450a90d1", + "reference": "53f86497ccd01677e22435cfb7262599450a90d1", "shasum": "" }, "require": { @@ -139,6 +139,7 @@ "require-dev": { "psr/log": "~1.0", "symfony/event-dispatcher": "~2.1", + "symfony/phpunit-bridge": "~2.7", "symfony/process": "~2.1" }, "suggest": { @@ -173,26 +174,29 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2015-01-25 04:39:26" + "time": "2015-03-13 17:37:22" }, { "name": "symfony/finder", - "version": "v2.6.4", + "version": "v2.6.5", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "16513333bca64186c01609961a2bb1b95b5e1355" + "reference": "bebc7479c566fa4f14b9bcef9e32e719eabec74e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355", - "reference": "16513333bca64186c01609961a2bb1b95b5e1355", + "url": "https://api.github.com/repos/symfony/Finder/zipball/bebc7479c566fa4f14b9bcef9e32e719eabec74e", + "reference": "bebc7479c566fa4f14b9bcef9e32e719eabec74e", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, "type": "library", "extra": { "branch-alias": { @@ -220,26 +224,29 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2015-01-03 08:01:59" + "time": "2015-03-12 10:28:44" }, { "name": "symfony/process", - "version": "v2.6.4", + "version": "v2.6.5", "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/Process.git", - "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" + "reference": "4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", - "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "url": "https://api.github.com/repos/symfony/Process/zipball/4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc", + "reference": "4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, "type": "library", "extra": { "branch-alias": { @@ -267,7 +274,7 @@ ], "description": "Symfony Process Component", "homepage": "http://symfony.com", - "time": "2015-01-25 04:39:26" + "time": "2015-03-12 10:28:44" } ], "packages-dev": [ @@ -1177,22 +1184,25 @@ }, { "name": "symfony/yaml", - "version": "v2.6.4", + "version": "v2.6.5", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8" + "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8", - "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/0cd8e72071e46e15fc072270ae39ea1b66b10a9d", + "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, "type": "library", "extra": { "branch-alias": { @@ -1220,7 +1230,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2015-01-25 04:39:26" + "time": "2015-03-12 10:28:44" } ], "aliases": [], From 66b73ea4560daf20cc64a74c60749721e273e71d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Mar 2015 01:29:49 +0000 Subject: [PATCH 81/83] Revert "Disable overwrites when no-ansi is present, fixes #3612" This reverts commit e0d36e19eb8a5c96ccad3d145faf9024727e856c. Conflicts: src/Composer/IO/ConsoleIO.php --- src/Composer/IO/ConsoleIO.php | 9 --------- tests/Composer/Test/IO/ConsoleIOTest.php | 16 +++++----------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index 7de4d8ede..38e722bf5 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -163,15 +163,6 @@ class ConsoleIO extends BaseIO $output = $this->output; } - if (!$output->isDecorated()) { - if (!$messages) { - return; - } - - $this->doWrite($messages, count($messages) === 1 || $newline, $stderr); - return; - } - // messages can be an array, let's convert it to string anyway $messages = join($newline ? "\n" : '', (array) $messages); diff --git a/tests/Composer/Test/IO/ConsoleIOTest.php b/tests/Composer/Test/IO/ConsoleIOTest.php index 0edd34d99..d0af8cb42 100644 --- a/tests/Composer/Test/IO/ConsoleIOTest.php +++ b/tests/Composer/Test/IO/ConsoleIOTest.php @@ -99,27 +99,21 @@ class ConsoleIOTest extends TestCase ->method('write') ->with($this->equalTo('something (strlen = 23)')); $outputMock->expects($this->at(1)) - ->method('isDecorated') - ->willReturn(true); - $outputMock->expects($this->at(2)) ->method('write') ->with($this->equalTo(str_repeat("\x08", 23)), $this->equalTo(false)); - $outputMock->expects($this->at(3)) + $outputMock->expects($this->at(2)) ->method('write') ->with($this->equalTo('shorter (12)'), $this->equalTo(false)); - $outputMock->expects($this->at(4)) + $outputMock->expects($this->at(3)) ->method('write') ->with($this->equalTo(str_repeat(' ', 11)), $this->equalTo(false)); - $outputMock->expects($this->at(5)) + $outputMock->expects($this->at(4)) ->method('write') ->with($this->equalTo(str_repeat("\x08", 11)), $this->equalTo(false)); - $outputMock->expects($this->at(6)) - ->method('isDecorated') - ->willReturn(true); - $outputMock->expects($this->at(7)) + $outputMock->expects($this->at(5)) ->method('write') ->with($this->equalTo(str_repeat("\x08", 12)), $this->equalTo(false)); - $outputMock->expects($this->at(8)) + $outputMock->expects($this->at(6)) ->method('write') ->with($this->equalTo('something longer than initial (34)')); From c5cd184767001f34177da99e91f7a6dcf8ad27f6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 24 Mar 2015 01:36:30 +0000 Subject: [PATCH 82/83] Revert 331425bcb3cd13a5d5d807c13c6a651229b56ac8 as well, fixes #3612 --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 4aeae4e05..7c72c21c0 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -158,7 +158,7 @@ class RemoteFilesystem $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { - $this->io->writeError(" Downloading: Connecting...", !$this->io->isDecorated()); + $this->io->writeError(" Downloading: Connecting...", false); } $errorMessage = ''; From 7cb9b9a985f0684d5c94bc1afcdb2d228115bbfb Mon Sep 17 00:00:00 2001 From: Morgan Campbell Date: Wed, 25 Mar 2015 08:32:29 -0500 Subject: [PATCH 83/83] Update 01-basic-usage.md Added a missing "the" so the sentence flows a little better. --- doc/01-basic-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index ef72f556c..bc18f3357 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -140,7 +140,7 @@ versions from `composer.json` and create the lock file after executing the `upd command. This means that if any of the dependencies get a new version, you won't get the updates -automatically. To update to the new version, use `update` command. This will fetch +automatically. To update to the new version, use the `update` command. This will fetch the latest matching versions (according to your `composer.json` file) and also update the lock file with the new version.