From 53191eb0febfd114a095111a7983edf2c5dc334f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 11:55:57 +0200 Subject: [PATCH 1/9] Remove recommend, make suggest informational, add require-dev, fixes #78, fixes #510 --- src/Composer/Command/InstallCommand.php | 6 +-- src/Composer/Command/UpdateCommand.php | 8 ++-- src/Composer/DependencyResolver/Solver.php | 12 ----- src/Composer/Installer.php | 50 ++++++--------------- src/Composer/Package/AliasPackage.php | 18 +++----- src/Composer/Package/BasePackage.php | 11 +++-- src/Composer/Package/Dumper/ArrayDumper.php | 13 ++++-- src/Composer/Package/Loader/ArrayLoader.php | 10 +++-- src/Composer/Package/MemoryPackage.php | 14 +++--- src/Composer/Package/PackageInterface.php | 16 +++---- 10 files changed, 61 insertions(+), 97 deletions(-) diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index 1f711c334..bb6c636b6 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -32,8 +32,7 @@ class InstallCommand extends Command ->setDefinition(array( new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'), - new InputOption('no-install-recommends', null, InputOption::VALUE_NONE, 'Do not install recommended packages (ignored when installing from an existing lock file).'), - new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages (ignored when installing from an existing lock file).'), + new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'), )) ->setHelp(<<install command reads the composer.json file from the @@ -57,8 +56,7 @@ EOT ->setDryRun($input->getOption('dry-run')) ->setVerbose($input->getOption('verbose')) ->setPreferSource($input->getOption('prefer-source')) - ->setInstallRecommends(!$input->getOption('no-install-recommends')) - ->setInstallSuggests($input->getOption('install-suggests')) + ->setDevMode($input->getOption('dev')) ; return $install->run() ? 0 : 1; diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 44bd17b90..ffc848d87 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -30,8 +30,7 @@ class UpdateCommand extends Command ->setDefinition(array( new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'), - new InputOption('no-install-recommends', null, InputOption::VALUE_NONE, 'Do not install recommended packages.'), - new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages.'), + new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'), )) ->setHelp(<<update command reads the composer.json file from the @@ -55,11 +54,10 @@ EOT ->setDryRun($input->getOption('dry-run')) ->setVerbose($input->getOption('verbose')) ->setPreferSource($input->getOption('prefer-source')) - ->setInstallRecommends(!$input->getOption('no-install-recommends')) - ->setInstallSuggests($input->getOption('install-suggests')) + ->setDevMode($input->getOption('dev')) ->setUpdate(true) ; - return $install->run(); + return $install->run() ? 0 : 1; } } diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index c19aa212b..6d939f063 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -283,18 +283,6 @@ class Solver } } } - - foreach ($package->getRecommends() as $link) { - foreach ($this->pool->whatProvides($link->getTarget(), $link->getConstraint()) as $recommend) { - $workQueue->enqueue($recommend); - } - } - - foreach ($package->getSuggests() as $link) { - foreach ($this->pool->whatProvides($link->getTarget(), $link->getConstraint()) as $suggest) { - $workQueue->enqueue($suggest); - } - } } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 794d42ead..bd8b15827 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -77,10 +77,9 @@ class Installer protected $eventDispatcher; protected $preferSource = false; + protected $devMode = false; protected $dryRun = false; protected $verbose = false; - protected $installRecommends = true; - protected $installSuggests = false; protected $update = false; /** @@ -332,14 +331,6 @@ class Installer { $links = $this->package->getRequires(); - if ($this->installRecommends) { - $links = array_merge($links, $this->package->getRecommends()); - } - - if ($this->installSuggests) { - $links = array_merge($links, $this->package->getSuggests()); - } - return $links; } @@ -379,7 +370,7 @@ class Installer * @param boolean $dryRun * @return Installer */ - public function setDryRun($dryRun=true) + public function setDryRun($dryRun = true) { $this->dryRun = (boolean) $dryRun; @@ -387,53 +378,40 @@ class Installer } /** - * install recommend packages - * - * @param boolean $noInstallRecommends - * @return Installer - */ - public function setInstallRecommends($installRecommends=true) - { - $this->installRecommends = (boolean) $installRecommends; - - return $this; - } - - /** - * also install suggested packages + * prefer source installation * - * @param boolean $installSuggests + * @param boolean $preferSource * @return Installer */ - public function setInstallSuggests($installSuggests=true) + public function setPreferSource($preferSource = true) { - $this->installSuggests = (boolean) $installSuggests; + $this->preferSource = (boolean) $preferSource; return $this; } /** - * prefer source installation + * update packages * - * @param boolean $preferSource + * @param boolean $update * @return Installer */ - public function setPreferSource($preferSource=true) + public function setUpdate($update = true) { - $this->preferSource = (boolean) $preferSource; + $this->update = (boolean) $update; return $this; } /** - * update packages + * enables dev packages * * @param boolean $update * @return Installer */ - public function setUpdate($update=true) + public function setDevMode($devMode = true) { - $this->update = (boolean) $update; + $this->devMode = (boolean) $devMode; return $this; } @@ -444,7 +422,7 @@ class Installer * @param boolean $verbose * @return Installer */ - public function setVerbose($verbose=true) + public function setVerbose($verbose = true) { $this->verbose = (boolean) $verbose; diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php index e453e3068..af5887c9e 100644 --- a/src/Composer/Package/AliasPackage.php +++ b/src/Composer/Package/AliasPackage.php @@ -52,7 +52,7 @@ class AliasPackage extends BasePackage $this->dev = VersionParser::isDev($version); // replace self.version dependencies - foreach (array('requires', 'recommends', 'suggests') as $type) { + foreach (array('requires', 'devRequires') as $type) { $links = $aliasOf->{'get'.ucfirst($type)}(); foreach ($links as $index => $link) { // link is self.version, but must be replacing also the replaced version @@ -141,17 +141,9 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - public function getRecommends() + public function getDevRequires() { - return $this->recommends; - } - - /** - * {@inheritDoc} - */ - public function getSuggests() - { - return $this->suggests; + return $this->devRequires; } /** @@ -266,6 +258,10 @@ class AliasPackage extends BasePackage { return $this->aliasOf->getHomepage(); } + public function getSuggests() + { + return $this->aliasOf->getSuggests(); + } public function getAuthors() { return $this->aliasOf->getAuthors(); diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index 90fb67868..171c5ee08 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -25,12 +25,11 @@ use Composer\Repository\PlatformRepository; abstract class BasePackage implements PackageInterface { public static $supportedLinkTypes = array( - 'require' => 'requires', - 'conflict' => 'conflicts', - 'provide' => 'provides', - 'replace' => 'replaces', - 'recommend' => 'recommends', - 'suggest' => 'suggests', + 'require' => array('description' => 'requires', 'method' => 'requires'), + 'conflict' => array('description' => 'conflicts', 'method' => 'conflicts'), + 'provide' => array('description' => 'provides', 'method' => 'provides'), + 'replace' => array('description' => 'replaces', 'method' => 'replaces'), + 'require-dev' => array('description' => 'requires (for development)', 'method' => 'devRequires'), ); protected $name; diff --git a/src/Composer/Package/Dumper/ArrayDumper.php b/src/Composer/Package/Dumper/ArrayDumper.php index 188d55c5c..ed25e656b 100644 --- a/src/Composer/Package/Dumper/ArrayDumper.php +++ b/src/Composer/Package/Dumper/ArrayDumper.php @@ -12,6 +12,7 @@ namespace Composer\Package\Dumper; +use Composer\Package\BasePackage; use Composer\Package\PackageInterface; /** @@ -26,7 +27,6 @@ class ArrayDumper 'binaries' => 'bin', 'scripts', 'type', - 'names', 'extra', 'installationSource' => 'installation-source', 'license', @@ -36,6 +36,7 @@ class ArrayDumper 'keywords', 'autoload', 'repositories', + 'includePaths' => 'include-path', ); $data = array(); @@ -64,14 +65,18 @@ class ArrayDumper $data['dist']['shasum'] = $package->getDistSha1Checksum(); } - foreach (array('require', 'conflict', 'provide', 'replace', 'suggest', 'recommend') as $linkType) { - if ($links = $package->{'get'.ucfirst($linkType).'s'}()) { + foreach (BasePackage::$supportedLinkTypes as $type => $opts) { + if ($links = $package->{'get'.ucfirst($opts['method'])}()) { foreach ($links as $link) { - $data[$linkType][$link->getTarget()] = $link->getPrettyConstraint(); + $data[$type][$link->getTarget()] = $link->getPrettyConstraint(); } } } + if ($packages = $package->getSuggests()) { + $data['suggest'] = $packages; + } + foreach ($keys as $method => $key) { if (is_numeric($method)) { $method = $key; diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php index b44d6b950..0e706bad9 100644 --- a/src/Composer/Package/Loader/ArrayLoader.php +++ b/src/Composer/Package/Loader/ArrayLoader.php @@ -156,15 +156,19 @@ class ArrayLoader } } - foreach (Package\BasePackage::$supportedLinkTypes as $type => $description) { + foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) { if (isset($config[$type])) { - $method = 'set'.ucfirst($description); + $method = 'set'.ucfirst($opts['method']); $package->{$method}( - $this->loadLinksFromConfig($package, $description, $config[$type]) + $this->loadLinksFromConfig($package, $opts['description'], $config[$type]) ); } } + if (isset($config['suggest']) && is_array($config['suggest'])) { + $package->setSuggests($config['suggest']); + } + if (isset($config['autoload'])) { $package->setAutoload($config['autoload']); } diff --git a/src/Composer/Package/MemoryPackage.php b/src/Composer/Package/MemoryPackage.php index 8944f9b47..4a8f55cde 100644 --- a/src/Composer/Package/MemoryPackage.php +++ b/src/Composer/Package/MemoryPackage.php @@ -53,7 +53,7 @@ class MemoryPackage extends BasePackage protected $conflicts = array(); protected $provides = array(); protected $replaces = array(); - protected $recommends = array(); + protected $devRequires = array(); protected $suggests = array(); protected $autoload = array(); protected $includePaths = array(); @@ -484,25 +484,25 @@ class MemoryPackage extends BasePackage /** * Set the recommended packages * - * @param array $recommends A set of package links + * @param array $devRequires A set of package links */ - public function setRecommends(array $recommends) + public function setDevRequires(array $devRequires) { - $this->recommends = $recommends; + $this->devRequires = $devRequires; } /** * {@inheritDoc} */ - public function getRecommends() + public function getDevRequires() { - return $this->recommends; + return $this->devRequires; } /** * Set the suggested packages * - * @param array $suggests A set of package links + * @param array $suggests A set of package names/comments */ public function setSuggests(array $suggests) { diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 82a51e8b5..5b8d2ddb2 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -220,20 +220,18 @@ interface PackageInterface function getReplaces(); /** - * Returns a set of links to packages which are recommended in - * combination with this package. These would most likely be installed - * automatically in combination with this package. + * Returns a set of links to packages which are required to develop + * this package. These are installed if in dev mode. * - * @return array An array of package links defining recommended packages + * @return array An array of package links defining packages required for development */ - function getRecommends(); + function getDevRequires(); /** - * Returns a set of links to packages which are suggested in combination - * with this package. These can be suggested to the user, but will not be - * automatically installed with this package. + * Returns a set of package names and reasons why they are useful in + * combination with this package. * - * @return array An array of package links defining suggested packages + * @return array An array of package suggestions with descriptions */ function getSuggests(); From e922404f191316cda27dcfa81473de0e5323c6c1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 11:56:13 +0200 Subject: [PATCH 2/9] Update/add tests --- .../Test/Package/Dumper/ArrayDumperTest.php | 81 +++++++++++++++--- .../Test/Package/Loader/ArrayLoaderTest.php | 85 +++++++++++++++++++ .../Repository/FilesystemRepositoryTest.php | 2 +- 3 files changed, 154 insertions(+), 14 deletions(-) diff --git a/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php b/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php index eab3450bf..2396fbfc9 100644 --- a/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php +++ b/tests/Composer/Test/Package/Dumper/ArrayDumperTest.php @@ -14,6 +14,8 @@ namespace Composer\Test\Package\Dumper; use Composer\Package\Dumper\ArrayDumper; use Composer\Package\MemoryPackage; +use Composer\Package\Link; +use Composer\Package\LinkConstraint\VersionConstraint; class ArrayDumperTest extends \PHPUnit_Framework_TestCase { @@ -27,13 +29,13 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase $package = new MemoryPackage('foo', '1.0.0.0', '1.0'); $config = $this->dumper->dump($package); - $this->assertEquals(array('name', 'version', 'version_normalized', 'type', 'names'), array_keys($config)); + $this->assertEquals(array('name', 'version', 'version_normalized', 'type'), array_keys($config)); } /** * @dataProvider getKeys */ - public function testKeys($key, $value, $expectedValue = null, $method = null) + public function testKeys($key, $value, $method = null, $expectedValue = null) { $package = new MemoryPackage('foo', '1.0.0.0', '1.0'); @@ -50,17 +52,70 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase public function getKeys() { return array( - array('time', new \DateTime('2012-02-01'), '2012-02-01 00:00:00', 'ReleaseDate'), - array('authors', array('Nils Adermann ', 'Jordi Boggiano ')), - array('homepage', 'http://getcomposer.org'), - array('description', 'Package Manager'), - array('keywords', array('package', 'dependency', 'autoload')), - array('bin', array('bin/composer'), null, 'binaries'), - array('license', array('MIT')), - array('autoload', array('psr-0' => array('Composer' => 'src/'))), - array('repositories', array('packagist' => false)), - array('scripts', array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate')), - array('extra', array('class' => 'MyVendor\\Installer')), + array( + 'time', + new \DateTime('2012-02-01'), + 'ReleaseDate', + '2012-02-01 00:00:00', + ), + array( + 'authors', + array('Nils Adermann ', 'Jordi Boggiano ') + ), + array( + 'homepage', + 'http://getcomposer.org' + ), + array( + 'description', + 'Package Manager' + ), + array( + 'keywords', + array('package', 'dependency', 'autoload') + ), + array( + 'bin', + array('bin/composer'), + 'binaries' + ), + array( + 'license', + array('MIT') + ), + array( + 'autoload', + array('psr-0' => array('Composer' => 'src/')) + ), + array( + 'repositories', + array('packagist' => false) + ), + array( + 'scripts', + array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate') + ), + array( + 'extra', + array('class' => 'MyVendor\\Installer') + ), + array( + 'require', + array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires', '1.0.0')), + 'requires', + array('foo/bar' => '1.0.0'), + ), + array( + 'require-dev', + array(new Link('foo', 'foo/bar', new VersionConstraint('=', '1.0.0.0'), 'requires (for development)', '1.0.0')), + 'devRequires', + array('foo/bar' => '1.0.0'), + ), + array( + 'suggest', + array('foo/bar' => 'very useful package'), + 'suggests' + ), ); } } diff --git a/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php index 98c595243..0bee2bf1a 100644 --- a/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ArrayLoaderTest.php @@ -13,6 +13,7 @@ namespace Composer\Test\Package\Loader; use Composer\Package\Loader\ArrayLoader; +use Composer\Package\Dumper\ArrayDumper; class ArrayLoaderTest extends \PHPUnit_Framework_TestCase { @@ -35,4 +36,88 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase $replaces = $package->getReplaces(); $this->assertEquals('== 1.2.3.4', (string) $replaces[0]->getConstraint()); } + + public function testTypeDefault() + { + $config = array( + 'name' => 'A', + 'version' => '1.0', + ); + + $package = $this->loader->load($config); + $this->assertEquals('library', $package->getType()); + + $config = array( + 'name' => 'A', + 'version' => '1.0', + 'type' => 'foo', + ); + + $package = $this->loader->load($config); + $this->assertEquals('foo', $package->getType()); + } + + public function testNormalizedVersionOptimization() + { + $config = array( + 'name' => 'A', + 'version' => '1.2.3', + ); + + $package = $this->loader->load($config); + $this->assertEquals('1.2.3.0', $package->getVersion()); + + $config = array( + 'name' => 'A', + 'version' => '1.2.3', + 'version_normalized' => '1.2.3.4', + ); + + $package = $this->loader->load($config); + $this->assertEquals('1.2.3.4', $package->getVersion()); + } + + public function testParseDump() + { + $config = array( + 'name' => 'A/B', + 'version' => '1.2.3', + 'version_normalized' => '1.2.3.0', + 'description' => 'Foo bar', + 'type' => 'library', + 'keywords' => array('a', 'b', 'c'), + 'homepage' => 'http://example.com', + 'license' => array('MIT', 'GPLv3'), + 'authors' => array( + array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org'), + ), + 'require' => array( + 'foo/bar' => '1.0', + ), + 'require-dev' => array( + 'foo/baz' => '1.0', + ), + 'replace' => array( + 'foo/qux' => '1.0', + ), + 'conflict' => array( + 'foo/quux' => '1.0', + ), + 'provide' => array( + 'foo/quuux' => '1.0', + ), + 'autoload' => array( + 'psr-0' => array('Ns\Prefix' => 'path'), + 'classmap' => array('path', 'path2'), + ), + 'include-path' => array('path3', 'path4'), + 'target-dir' => 'some/prefix', + 'extra' => array('random' => array('things' => 'of', 'any' => 'shape')), + 'bin' => array('bin1', 'bin/foo'), + ); + + $package = $this->loader->load($config); + $dumper = new ArrayDumper; + $this->assertEquals($config, $dumper->dump($package)); + } } diff --git a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php index c9abcdb76..fee07dfc8 100644 --- a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php +++ b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php @@ -95,7 +95,7 @@ class FilesystemRepositoryTest extends TestCase ->expects($this->once()) ->method('write') ->with(array( - array('name' => 'mypkg', 'type' => 'library', 'names' => array('mypkg'), 'version' => '0.1.10', 'version_normalized' => '0.1.10.0') + array('name' => 'mypkg', 'type' => 'library', 'version' => '0.1.10', 'version_normalized' => '0.1.10.0') )); $repository->addPackage($this->getPackage('mypkg', '0.1.10')); From bb4283c07f56d4b0218fe45c29cf35d7f06204e4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 11:59:53 +0200 Subject: [PATCH 3/9] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e30a585c..09f21b61b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ * 1.0.0-alpha3 + * Schema: Added 'require-dev' for development-time requirements (tests, etc), install with --dev + * Schema: Removed 'recommend' + * Schema: 'suggest' is now informational and can use any description for a package, not only a constraint * Added caching of repository metadata (faster startup times & failover if packagist is down) * Added include_path support for legacy projects that are full of require_once statements * Added installation notifications API to allow better statistics on Composer repositories From e88a831bd1082dbd00b75fb2263d22da3654f7a0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 12:00:01 +0200 Subject: [PATCH 4/9] Update JSON schema --- res/composer-schema.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/composer-schema.json b/res/composer-schema.json index 3a43aba3e..c11ed953e 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -90,14 +90,14 @@ "description": "This is a hash of package name (keys) and version constraints (values) that this package provides in addition to this package's name.", "additionalProperties": true }, - "recommend": { + "require-dev": { "type": "object", - "description": "This is a hash of package name (keys) and version constraints (values) that this package recommends to be installed (typically this will be installed as well).", + "description": "This is a hash of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).", "additionalProperties": true }, "suggest": { "type": "object", - "description": "This is a hash of package name (keys) and version constraints (values) that this package suggests work well with it (typically this will only be suggested to the user).", + "description": "This is a hash of package name (keys) and descriptions (values) that this package suggests work well with it (this will be suggested to the user during installation).", "additionalProperties": true }, "config": { From e7027612846eaa532ffa50a57384836c019d71e2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 12:07:49 +0200 Subject: [PATCH 5/9] Output suggested packages after package installation --- src/Composer/Installer.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index bd8b15827..e459c94ca 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -273,10 +273,23 @@ class Installer $this->io->write('Nothing to install or update'); } + $suggestedPackages = array(); foreach ($operations as $operation) { if ($this->verbose) { $this->io->write((string) $operation); } + + // collect suggestions + if ('install' === $operation->getJobType()) { + foreach ($operation->getPackage()->getSuggests() as $target => $reason) { + $suggestedPackages[] = array( + 'source' => $operation->getPackage()->getPrettyName(), + 'target' => $target, + 'reason' => $reason, + ); + } + } + if (!$this->dryRun) { $this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation); @@ -306,15 +319,20 @@ class Installer } } + // dump suggestions + foreach ($suggestedPackages as $suggestion) { + $this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')'); + } + if (!$this->dryRun) { + // write lock if ($this->update || !$this->locker->isLocked()) { if ($this->locker->setLockData($localRepo->getPackages(), $aliases)) { $this->io->write('Writing lock file'); } } - $localRepo->write(); - + // write autoloader $this->io->write('Generating autoload files'); $generator = new AutoloadGenerator; $generator->dump($localRepo, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer'); From a04647aa8c0a2a3c21560fff337a01f4742fb1f9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 15:43:08 +0200 Subject: [PATCH 6/9] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 07a8c3c35..08c043c43 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ "symfony/finder": "2.1.*", "symfony/process": "2.1.*" }, - "recommend": { - "ext-zip": "*" + "suggest": { + "ext-zip": "Enabling the zip extension allows you to zip archives, and allows gzip compression of all internet traffic" }, "autoload": { "psr-0": { "Composer": "src/" } From 89e095b4b55c6bca1c3d36d97a937f01c1268e9f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 15:45:25 +0200 Subject: [PATCH 7/9] Handle --dev installs/updates --- src/Composer/Factory.php | 15 +- src/Composer/Installer.php | 148 +++++++++++------- .../Installer/InstallationManager.php | 30 ++-- src/Composer/Installer/InstallerInstaller.php | 25 +-- src/Composer/Installer/InstallerInterface.php | 14 +- src/Composer/Installer/LibraryInstaller.php | 34 ++-- .../Installer/MetapackageInstaller.php | 36 ++--- src/Composer/Package/Locker.php | 44 ++++-- src/Composer/Repository/RepositoryManager.php | 31 ++++ .../installer-v1/Installer/Custom.php | 9 +- .../installer-v2/Installer/Custom2.php | 9 +- .../installer-v3/Installer/Custom2.php | 9 +- .../Installer/InstallationManagerTest.php | 36 +++-- .../Test/Installer/InstallerInstallerTest.php | 18 +-- .../Test/Installer/LibraryInstallerTest.php | 36 ++--- .../Installer/MetapackageInstallerTest.php | 12 +- tests/Composer/Test/Package/LockerTest.php | 5 +- 17 files changed, 297 insertions(+), 214 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 1db5c11db..9f32ec27c 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -152,6 +152,7 @@ class Factory protected function addLocalRepository(RepositoryManager $rm, $vendorDir) { $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); + $rm->setLocalDevRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed_dev.json'))); } protected function addPackagistRepository(array $localConfig) @@ -202,18 +203,20 @@ class Factory protected function createInstallationManager(Repository\RepositoryManager $rm, Downloader\DownloadManager $dm, $vendorDir, $binDir, IOInterface $io) { $im = new Installer\InstallationManager($vendorDir); - $im->addInstaller(new Installer\LibraryInstaller($vendorDir, $binDir, $dm, $rm->getLocalRepository(), $io, null)); - $im->addInstaller(new Installer\InstallerInstaller($vendorDir, $binDir, $dm, $rm->getLocalRepository(), $io, $im)); - $im->addInstaller(new Installer\MetapackageInstaller($rm->getLocalRepository(), $io)); + $im->addInstaller(new Installer\LibraryInstaller($vendorDir, $binDir, $dm, $io, null)); + $im->addInstaller(new Installer\InstallerInstaller($vendorDir, $binDir, $dm, $io, $im, $rm->getLocalRepositories())); + $im->addInstaller(new Installer\MetapackageInstaller($io)); return $im; } protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im) { - foreach ($rm->getLocalRepository()->getPackages() as $package) { - if (!$im->isPackageInstalled($package)) { - $rm->getLocalRepository()->removePackage($package); + foreach ($rm->getLocalRepositories() as $repo) { + foreach ($repo->getPackages() as $package) { + if (!$im->isPackageInstalled($repo, $package)) { + $repo->removePackage($package); + } } } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index e459c94ca..dca27a6eb 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -122,33 +122,14 @@ class Installer $this->downloadManager->setPreferSource(true); } - // create local repo, this contains all packages that are installed in the local project - $localRepo = $this->repositoryManager->getLocalRepository(); // create installed repo, this contains all local packages + platform packages (php & extensions) - $installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository())); + $repos = array_merge($this->repositoryManager->getLocalRepositories(), array(new PlatformRepository())); + $installedRepo = new CompositeRepository($repos); if ($this->additionalInstalledRepository) { $installedRepo->addRepository($this->additionalInstalledRepository); } - // prepare aliased packages - if (!$this->update && $this->locker->isLocked()) { - $aliases = $this->locker->getAliases(); - } else { - $aliases = $this->package->getAliases(); - } - foreach ($aliases as $alias) { - foreach ($this->repositoryManager->findPackages($alias['package'], $alias['version']) as $package) { - $package->setAlias($alias['alias_normalized']); - $package->setPrettyAlias($alias['alias']); - $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); - } - foreach ($this->repositoryManager->getLocalRepository()->findPackages($alias['package'], $alias['version']) as $package) { - $package->setAlias($alias['alias_normalized']); - $package->setPrettyAlias($alias['alias']); - $this->repositoryManager->getLocalRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); - $this->repositoryManager->getLocalRepository()->removePackage($package); - } - } + $aliases = $this->aliasPackages(); // creating repository pool $pool = new Pool; @@ -157,34 +138,74 @@ class Installer $pool->addRepository($repository); } - // dispatch pre event if (!$this->dryRun) { + // dispatch pre event $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; $this->eventDispatcher->dispatchCommandEvent($eventName); } + $suggestedPackages = $this->doInstall($this->repositoryManager->getLocalRepository(), $installedRepo, $pool, $aliases); + if ($this->devMode) { + $devSuggested = $this->doInstall($this->repositoryManager->getLocalDevRepository(), $installedRepo, $pool, $aliases, true); + $suggestedPackages = array_merge($suggestedPackages, $devSuggested); + } + + // dump suggestions + foreach ($suggestedPackages as $suggestion) { + $this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')'); + } + + if (!$this->dryRun) { + // write lock + if ($this->update || !$this->locker->isLocked()) { + $updatedLock = $this->locker->setLockData( + $this->repositoryManager->getLocalRepository()->getPackages(), + $this->repositoryManager->getLocalDevRepository()->getPackages(), + $aliases + ); + if ($updatedLock) { + $this->io->write('Writing lock file'); + } + } + + // write autoloader + $this->io->write('Generating autoload files'); + $generator = new AutoloadGenerator; + $localRepos = new CompositeRepository($this->repositoryManager->getLocalRepositories()); + $generator->dump($localRepos, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer'); + + // dispatch post event + $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; + $this->eventDispatcher->dispatchCommandEvent($eventName); + } + + return true; + } + + protected function doInstall($localRepo, $installedRepo, $pool, $aliases, $devMode = false) + { // creating requirements request $installFromLock = false; $request = new Request($pool); if ($this->update) { - $this->io->write('Updating dependencies'); + $this->io->write('Updating '.($devMode ? 'dev ': '').'dependencies'); $request->updateAll(); - $links = $this->collectLinks(); + $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } elseif ($this->locker->isLocked()) { $installFromLock = true; - $this->io->write('Installing from lock file'); + $this->io->write('Installing '.($devMode ? 'dev ': '').'dependencies from lock file'); - if (!$this->locker->isFresh()) { + if (!$this->locker->isFresh() && !$devMode) { $this->io->write('Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies'); } - foreach ($this->locker->getLockedPackages() as $package) { + foreach ($this->locker->getLockedPackages($devMode) as $package) { $version = $package->getVersion(); foreach ($aliases as $alias) { if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) { @@ -196,15 +217,25 @@ class Installer $request->install($package->getName(), $constraint); } } else { - $this->io->write('Installing dependencies'); + $this->io->write('Installing '.($devMode ? 'dev ': '').'dependencies'); - $links = $this->collectLinks(); + $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } + // fix the version all installed packages that are not in the current local repo to prevent rogue updates + foreach ($installedRepo->getPackages() as $package) { + if ($package->getRepository() === $localRepo || $package->getRepository() instanceof PlatformRepository) { + continue; + } + + $constraint = new VersionConstraint('=', $package->getVersion()); + $request->install($package->getName(), $constraint); + } + // prepare solver $policy = new DefaultPolicy(); $solver = new Solver($policy, $pool, $installedRepo); @@ -261,16 +292,16 @@ class Installer } // anti-alias local repository to allow updates to work fine - foreach ($this->repositoryManager->getLocalRepository()->getPackages() as $package) { + foreach ($localRepo->getPackages() as $package) { if ($package instanceof AliasPackage) { - $this->repositoryManager->getLocalRepository()->addPackage(clone $package->getAliasOf()); - $this->repositoryManager->getLocalRepository()->removePackage($package); + $package->getRepository()->addPackage(clone $package->getAliasOf()); + $package->getRepository()->removePackage($package); } } // execute operations if (!$operations) { - $this->io->write('Nothing to install or update'); + $this->io->write('Nothing to install or update'); } $suggestedPackages = array(); @@ -311,7 +342,7 @@ class Installer } } } - $this->installationManager->execute($operation); + $this->installationManager->execute($localRepo, $operation); $this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation); @@ -319,37 +350,34 @@ class Installer } } - // dump suggestions - foreach ($suggestedPackages as $suggestion) { - $this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')'); + return $suggestedPackages; + } + + private function aliasPackages() + { + if (!$this->update && $this->locker->isLocked()) { + $aliases = $this->locker->getAliases(); + } else { + $aliases = $this->package->getAliases(); } - if (!$this->dryRun) { - // write lock - if ($this->update || !$this->locker->isLocked()) { - if ($this->locker->setLockData($localRepo->getPackages(), $aliases)) { - $this->io->write('Writing lock file'); + foreach ($aliases as $alias) { + foreach ($this->repositoryManager->findPackages($alias['package'], $alias['version']) as $package) { + $package->setAlias($alias['alias_normalized']); + $package->setPrettyAlias($alias['alias']); + $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); + } + foreach ($this->repositoryManager->getLocalRepositories() as $repo) { + foreach ($repo->findPackages($alias['package'], $alias['version']) as $package) { + $package->setAlias($alias['alias_normalized']); + $package->setPrettyAlias($alias['alias']); + $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); + $package->getRepository()->removePackage($package); } } - - // write autoloader - $this->io->write('Generating autoload files'); - $generator = new AutoloadGenerator; - $generator->dump($localRepo, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer'); - - // dispatch post event - $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; - $this->eventDispatcher->dispatchCommandEvent($eventName); } - return true; - } - - private function collectLinks() - { - $links = $this->package->getRequires(); - - return $links; + return $aliases; } /** diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 6f397b358..c015bd9f9 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -14,6 +14,7 @@ namespace Composer\Installer; use Composer\Package\PackageInterface; use Composer\Package\AliasPackage; +use Composer\Repository\RepositoryInterface; use Composer\Repository\NotifiableRepositoryInterface; use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\InstallOperation; @@ -95,32 +96,35 @@ class InstallationManager /** * Checks whether provided package is installed in one of the registered installers. * + * @param RepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance * * @return Boolean */ - public function isPackageInstalled(PackageInterface $package) + public function isPackageInstalled(RepositoryInterface $repo, PackageInterface $package) { - return $this->getInstaller($package->getType())->isInstalled($package); + return $this->getInstaller($package->getType())->isInstalled($repo, $package); } /** * Executes solver operation. * + * @param RepositoryInterface $repo repository in which to check * @param OperationInterface $operation operation instance */ - public function execute(OperationInterface $operation) + public function execute(RepositoryInterface $repo, OperationInterface $operation) { $method = $operation->getJobType(); - $this->$method($operation); + $this->$method($repo, $operation); } /** * Executes install operation. * + * @param RepositoryInterface $repo repository in which to check * @param InstallOperation $operation operation instance */ - public function install(InstallOperation $operation) + public function install(RepositoryInterface $repo, InstallOperation $operation) { $package = $operation->getPackage(); if ($package instanceof AliasPackage) { @@ -128,16 +132,17 @@ class InstallationManager $package->setInstalledAsAlias(true); } $installer = $this->getInstaller($package->getType()); - $installer->install($package); + $installer->install($repo, $package); $this->notifyInstall($package); } /** * Executes update operation. * + * @param RepositoryInterface $repo repository in which to check * @param InstallOperation $operation operation instance */ - public function update(UpdateOperation $operation) + public function update(RepositoryInterface $repo, UpdateOperation $operation) { $initial = $operation->getInitialPackage(); if ($initial instanceof AliasPackage) { @@ -154,27 +159,28 @@ class InstallationManager if ($initialType === $targetType) { $installer = $this->getInstaller($initialType); - $installer->update($initial, $target); + $installer->update($repo, $initial, $target); $this->notifyInstall($target); } else { - $this->getInstaller($initialType)->uninstall($initial); - $this->getInstaller($targetType)->install($target); + $this->getInstaller($initialType)->uninstall($repo, $initial); + $this->getInstaller($targetType)->install($repo, $target); } } /** * Uninstalls package. * + * @param RepositoryInterface $repo repository in which to check * @param UninstallOperation $operation operation instance */ - public function uninstall(UninstallOperation $operation) + public function uninstall(RepositoryInterface $repo, UninstallOperation $operation) { $package = $operation->getPackage(); if ($package instanceof AliasPackage) { $package = $package->getAliasOf(); } $installer = $this->getInstaller($package->getType()); - $installer->uninstall($package); + $installer->uninstall($repo, $package); } /** diff --git a/src/Composer/Installer/InstallerInstaller.php b/src/Composer/Installer/InstallerInstaller.php index a43d0f15a..9519d384b 100644 --- a/src/Composer/Installer/InstallerInstaller.php +++ b/src/Composer/Installer/InstallerInstaller.php @@ -33,17 +33,20 @@ class InstallerInstaller extends LibraryInstaller * @param string $vendorDir relative path for packages home * @param string $binDir relative path for binaries * @param DownloadManager $dm download manager - * @param WritableRepositoryInterface $repository repository controller * @param IOInterface $io io instance + * @param InstallationManager $im installation manager + * @param array $localRepositories array of WritableRepositoryInterface */ - public function __construct($vendorDir, $binDir, DownloadManager $dm, WritableRepositoryInterface $repository, IOInterface $io, InstallationManager $im) + public function __construct($vendorDir, $binDir, DownloadManager $dm, IOInterface $io, InstallationManager $im, array $localRepositories) { - parent::__construct($vendorDir, $binDir, $dm, $repository, $io, 'composer-installer'); + parent::__construct($vendorDir, $binDir, $dm, $io, 'composer-installer'); $this->installationManager = $im; - foreach ($repository->getPackages() as $package) { - if ('composer-installer' === $package->getType()) { - $this->registerInstaller($package); + foreach ($localRepositories as $repo) { + foreach ($repo->getPackages() as $package) { + if ('composer-installer' === $package->getType()) { + $this->registerInstaller($package); + } } } } @@ -51,28 +54,28 @@ class InstallerInstaller extends LibraryInstaller /** * {@inheritDoc} */ - public function install(PackageInterface $package) + public function install(WritableRepositoryInterface $repo, PackageInterface $package) { $extra = $package->getExtra(); if (empty($extra['class'])) { throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-installer packages should have a class defined in their extra key to be usable.'); } - parent::install($package); + parent::install($repo, $package); $this->registerInstaller($package); } /** * {@inheritDoc} */ - public function update(PackageInterface $initial, PackageInterface $target) + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) { $extra = $target->getExtra(); if (empty($extra['class'])) { throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-installer packages should have a class defined in their extra key to be usable.'); } - parent::update($initial, $target); + parent::update($repo, $initial, $target); $this->registerInstaller($target); } @@ -97,7 +100,7 @@ class InstallerInstaller extends LibraryInstaller } $extra = $package->getExtra(); - $installer = new $class($this->vendorDir, $this->binDir, $this->downloadManager, $this->repository, $this->io); + $installer = new $class($this->vendorDir, $this->binDir, $this->downloadManager, $this->io); $this->installationManager->addInstaller($installer); } } diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index 36c023b3b..3716ec6df 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -14,11 +14,13 @@ namespace Composer\Installer; use Composer\DependencyResolver\Operation\OperationInterface; use Composer\Package\PackageInterface; +use Composer\Repository\WritableRepositoryInterface; /** * Interface for the package installation manager. * * @author Konstantin Kudryashov + * @author Jordi Boggiano */ interface InstallerInterface { @@ -33,35 +35,39 @@ interface InstallerInterface /** * Checks that provided package is installed. * + * @param WritableRepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance * * @return Boolean */ - function isInstalled(PackageInterface $package); + function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package); /** * Installs specific package. * + * @param WritableRepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance */ - function install(PackageInterface $package); + function install(WritableRepositoryInterface $repo, PackageInterface $package); /** * Updates specific package. * + * @param WritableRepositoryInterface $repo repository in which to check * @param PackageInterface $initial already installed package version * @param PackageInterface $target updated version * * @throws InvalidArgumentException if $from package is not installed */ - function update(PackageInterface $initial, PackageInterface $target); + function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target); /** * Uninstalls specific package. * + * @param WritableRepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance */ - function uninstall(PackageInterface $package); + function uninstall(WritableRepositoryInterface $repo, PackageInterface $package); /** * Returns the installation path of a package diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index bef93cf55..baff5fdeb 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -30,7 +30,6 @@ class LibraryInstaller implements InstallerInterface protected $vendorDir; protected $binDir; protected $downloadManager; - protected $repository; protected $io; private $type; private $filesystem; @@ -41,14 +40,12 @@ class LibraryInstaller implements InstallerInterface * @param string $vendorDir relative path for packages home * @param string $binDir relative path for binaries * @param DownloadManager $dm download manager - * @param WritableRepositoryInterface $repository repository controller * @param IOInterface $io io instance * @param string $type package type that this installer handles */ - public function __construct($vendorDir, $binDir, DownloadManager $dm, WritableRepositoryInterface $repository, IOInterface $io, $type = 'library') + public function __construct($vendorDir, $binDir, DownloadManager $dm, IOInterface $io, $type = 'library') { $this->downloadManager = $dm; - $this->repository = $repository; $this->io = $io; $this->type = $type; @@ -68,37 +65,37 @@ class LibraryInstaller implements InstallerInterface /** * {@inheritDoc} */ - public function isInstalled(PackageInterface $package) + public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) { - return $this->repository->hasPackage($package) && is_readable($this->getInstallPath($package)); + return $repo->hasPackage($package) && is_readable($this->getInstallPath($package)); } /** * {@inheritDoc} */ - public function install(PackageInterface $package) + public function install(WritableRepositoryInterface $repo, PackageInterface $package) { $this->initializeVendorDir(); $downloadPath = $this->getInstallPath($package); // remove the binaries if it appears the package files are missing - if (!is_readable($downloadPath) && $this->repository->hasPackage($package)) { + if (!is_readable($downloadPath) && $repo->hasPackage($package)) { $this->removeBinaries($package); } $this->downloadManager->download($package, $downloadPath); $this->installBinaries($package); - if (!$this->repository->hasPackage($package)) { - $this->repository->addPackage(clone $package); + if (!$repo->hasPackage($package)) { + $repo->addPackage(clone $package); } } /** * {@inheritDoc} */ - public function update(PackageInterface $initial, PackageInterface $target) + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) { - if (!$this->repository->hasPackage($initial)) { + if (!$repo->hasPackage($initial)) { throw new \InvalidArgumentException('Package is not installed: '.$initial); } @@ -108,18 +105,18 @@ class LibraryInstaller implements InstallerInterface $this->removeBinaries($initial); $this->downloadManager->update($initial, $target, $downloadPath); $this->installBinaries($target); - $this->repository->removePackage($initial); - if (!$this->repository->hasPackage($target)) { - $this->repository->addPackage(clone $target); + $repo->removePackage($initial); + if (!$repo->hasPackage($target)) { + $repo->addPackage(clone $target); } } /** * {@inheritDoc} */ - public function uninstall(PackageInterface $package) + public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) { - if (!$this->repository->hasPackage($package)) { + if (!$repo->hasPackage($package)) { // TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125) return; throw new \InvalidArgumentException('Package is not installed: '.$package); @@ -129,7 +126,7 @@ class LibraryInstaller implements InstallerInterface $this->downloadManager->remove($package, $downloadPath); $this->removeBinaries($package); - $this->repository->removePackage($package); + $repo->removePackage($package); } /** @@ -138,6 +135,7 @@ class LibraryInstaller implements InstallerInterface public function getInstallPath(PackageInterface $package) { $targetDir = $package->getTargetDir(); + return ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName() . ($targetDir ? '/'.$targetDir : ''); } diff --git a/src/Composer/Installer/MetapackageInstaller.php b/src/Composer/Installer/MetapackageInstaller.php index ceee0f1a3..9dcdbd3d0 100644 --- a/src/Composer/Installer/MetapackageInstaller.php +++ b/src/Composer/Installer/MetapackageInstaller.php @@ -12,7 +12,6 @@ namespace Composer\Installer; -use Composer\IO\IOInterface; use Composer\Repository\WritableRepositoryInterface; use Composer\Package\PackageInterface; @@ -23,19 +22,6 @@ use Composer\Package\PackageInterface; */ class MetapackageInstaller implements InstallerInterface { - protected $repository; - protected $io; - - /** - * @param WritableRepositoryInterface $repository repository controller - * @param IOInterface $io io instance - */ - public function __construct(WritableRepositoryInterface $repository, IOInterface $io) - { - $this->repository = $repository; - $this->io = $io; - } - /** * {@inheritDoc} */ @@ -47,44 +33,44 @@ class MetapackageInstaller implements InstallerInterface /** * {@inheritDoc} */ - public function isInstalled(PackageInterface $package) + public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) { - return $this->repository->hasPackage($package); + return $repo->hasPackage($package); } /** * {@inheritDoc} */ - public function install(PackageInterface $package) + public function install(WritableRepositoryInterface $repo, PackageInterface $package) { - $this->repository->addPackage(clone $package); + $repo->addPackage(clone $package); } /** * {@inheritDoc} */ - public function update(PackageInterface $initial, PackageInterface $target) + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) { - if (!$this->repository->hasPackage($initial)) { + if (!$repo->hasPackage($initial)) { throw new \InvalidArgumentException('Package is not installed: '.$initial); } - $this->repository->removePackage($initial); - $this->repository->addPackage(clone $target); + $repo->removePackage($initial); + $repo->addPackage(clone $target); } /** * {@inheritDoc} */ - public function uninstall(PackageInterface $package) + public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) { - if (!$this->repository->hasPackage($package)) { + if (!$repo->hasPackage($package)) { // TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125) return; throw new \InvalidArgumentException('Package is not installed: '.$package); } - $this->repository->removePackage($package); + $repo->removePackage($package); } /** diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index cc5112835..5f11e419d 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -69,13 +69,17 @@ class Locker * * @return array */ - public function getLockedPackages() + public function getLockedPackages($dev = false) { $lockList = $this->getLockData(); $packages = array(); - foreach ($lockList['packages'] as $info) { + + $lockedPackages = $dev ? $lockList['packages-dev'] : $lockList['packages']; + $repo = $dev ? $this->repositoryManager->getLocalDevRepository() : $this->repositoryManager->getLocalRepository(); + + foreach ($lockedPackages as $info) { $resolvedVersion = !empty($info['alias']) ? $info['alias'] : $info['version']; - $package = $this->repositoryManager->getLocalRepository()->findPackage($info['package'], $resolvedVersion); + $package = $repo->findPackage($info['package'], $resolvedVersion); if (!$package) { $package = $this->repositoryManager->findPackage($info['package'], $info['version']); @@ -120,18 +124,37 @@ class Locker * Locks provided data into lockfile. * * @param array $packages array of packages + * @param array $packages array of dev packages * @param array $aliases array of aliases * * @return Boolean */ - public function setLockData(array $packages, array $aliases) + public function setLockData(array $packages, array $devPackages, array $aliases) { $lock = array( 'hash' => $this->hash, 'packages' => array(), + 'packages-dev' => array(), 'aliases' => $aliases, ); + $lock['packages'] = $this->lockPackages($packages); + $lock['packages-dev'] = $this->lockPackages($devPackages); + + if (!$this->isLocked() || $lock !== $this->getLockData()) { + $this->lockFile->write($lock); + $this->lockDataCache = null; + + return true; + } + + return false; + } + + private function lockPackages(array $packages) + { + $locked = array(); + foreach ($packages as $package) { $name = $package->getPrettyName(); $version = $package->getPrettyVersion(); @@ -152,20 +175,13 @@ class Locker $spec['alias'] = $package->getAlias(); } - $lock['packages'][] = $spec; + $locked[] = $spec; } - usort($lock['packages'], function ($a, $b) { + usort($locked, function ($a, $b) { return strcmp($a['package'], $b['package']); }); - if (!$this->isLocked() || $lock !== $this->getLockData()) { - $this->lockFile->write($lock); - $this->lockDataCache = null; - - return true; - } - - return false; + return $locked; } } diff --git a/src/Composer/Repository/RepositoryManager.php b/src/Composer/Repository/RepositoryManager.php index 8dd684082..febce81a3 100644 --- a/src/Composer/Repository/RepositoryManager.php +++ b/src/Composer/Repository/RepositoryManager.php @@ -25,6 +25,7 @@ use Composer\Config; class RepositoryManager { private $localRepository; + private $localDevRepository; private $repositories = array(); private $repositoryClasses = array(); private $io; @@ -140,4 +141,34 @@ class RepositoryManager { return $this->localRepository; } + + /** + * Sets localDev repository for the project. + * + * @param RepositoryInterface $repository repository instance + */ + public function setLocalDevRepository(RepositoryInterface $repository) + { + $this->localDevRepository = $repository; + } + + /** + * Returns localDev repository for the project. + * + * @return RepositoryInterface + */ + public function getLocalDevRepository() + { + return $this->localDevRepository; + } + + /** + * Returns all local repositories for the project. + * + * @return array[RepositoryInterface] + */ + public function getLocalRepositories() + { + return array($this->localRepository, $this->localDevRepository); + } } diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php b/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php index 4bb58ded8..cfda3c3d3 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php @@ -4,15 +4,16 @@ namespace Installer; use Composer\Installer\InstallerInterface; use Composer\Package\PackageInterface; +use Composer\Repository\WritableRepositoryInterface; class Custom implements InstallerInterface { public $version = 'installer-v1'; public function supports($packageType) {} - public function isInstalled(PackageInterface $package) {} - public function install(PackageInterface $package) {} - public function update(PackageInterface $initial, PackageInterface $target) {} - public function uninstall(PackageInterface $package) {} + public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function install(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {} + public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php b/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php index edd264428..52f46371b 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php @@ -4,15 +4,16 @@ namespace Installer; use Composer\Installer\InstallerInterface; use Composer\Package\PackageInterface; +use Composer\Repository\WritableRepositoryInterface; class Custom2 implements InstallerInterface { public $version = 'installer-v2'; public function supports($packageType) {} - public function isInstalled(PackageInterface $package) {} - public function install(PackageInterface $package) {} - public function update(PackageInterface $initial, PackageInterface $target) {} - public function uninstall(PackageInterface $package) {} + public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function install(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {} + public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php b/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php index db211bed5..ca8ad7897 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php @@ -4,15 +4,16 @@ namespace Installer; use Composer\Installer\InstallerInterface; use Composer\Package\PackageInterface; +use Composer\Repository\WritableRepositoryInterface; class Custom2 implements InstallerInterface { public $version = 'installer-v3'; public function supports($packageType) {} - public function isInstalled(PackageInterface $package) {} - public function install(PackageInterface $package) {} - public function update(PackageInterface $initial, PackageInterface $target) {} - public function uninstall(PackageInterface $package) {} + public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function install(WritableRepositoryInterface $repo, PackageInterface $package) {} + public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {} + public function uninstall(WritableRepositoryInterface $repo, PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/InstallationManagerTest.php b/tests/Composer/Test/Installer/InstallationManagerTest.php index 941157a29..f14c08c84 100644 --- a/tests/Composer/Test/Installer/InstallationManagerTest.php +++ b/tests/Composer/Test/Installer/InstallationManagerTest.php @@ -19,6 +19,11 @@ use Composer\DependencyResolver\Operation\UninstallOperation; class InstallationManagerTest extends \PHPUnit_Framework_TestCase { + public function setUp() + { + $this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface'); + } + public function testVendorDirOutsideTheWorkingDir() { $manager = new InstallationManager(realpath(getcwd().'/../')); @@ -67,22 +72,23 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $this->createPackageMock(), $this->createPackageMock() ); + $manager ->expects($this->once()) ->method('install') - ->with($installOperation); + ->with($this->repository, $installOperation); $manager ->expects($this->once()) ->method('uninstall') - ->with($removeOperation); + ->with($this->repository, $removeOperation); $manager ->expects($this->once()) ->method('update') - ->with($updateOperation); + ->with($this->repository, $updateOperation); - $manager->execute($installOperation); - $manager->execute($removeOperation); - $manager->execute($updateOperation); + $manager->execute($this->repository, $installOperation); + $manager->execute($this->repository, $removeOperation); + $manager->execute($this->repository, $updateOperation); } public function testInstall() @@ -108,9 +114,9 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $installer ->expects($this->once()) ->method('install') - ->with($package); + ->with($this->repository, $package); - $manager->install($operation); + $manager->install($this->repository, $operation); } public function testUpdateWithEqualTypes() @@ -141,9 +147,9 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $installer ->expects($this->once()) ->method('update') - ->with($initial, $target); + ->with($this->repository, $initial, $target); - $manager->update($operation); + $manager->update($this->repository, $operation); } public function testUpdateWithNotEqualTypes() @@ -183,14 +189,14 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $libInstaller ->expects($this->once()) ->method('uninstall') - ->with($initial); + ->with($this->repository, $initial); $bundleInstaller ->expects($this->once()) ->method('install') - ->with($target); + ->with($this->repository, $target); - $manager->update($operation); + $manager->update($this->repository, $operation); } public function testUninstall() @@ -210,7 +216,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $installer ->expects($this->once()) ->method('uninstall') - ->with($package); + ->with($this->repository, $package); $installer ->expects($this->once()) @@ -218,7 +224,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase ->with('library') ->will($this->returnValue(true)); - $manager->uninstall($operation); + $manager->uninstall($this->repository, $operation); } public function testGetVendorPathAbsolute() diff --git a/tests/Composer/Test/Installer/InstallerInstallerTest.php b/tests/Composer/Test/Installer/InstallerInstallerTest.php index eab2d948a..2c107c32c 100644 --- a/tests/Composer/Test/Installer/InstallerInstallerTest.php +++ b/tests/Composer/Test/Installer/InstallerInstallerTest.php @@ -34,11 +34,9 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); - $this->repository = $this->getMockBuilder('Composer\Repository\WritableRepositoryInterface') - ->getMock(); + $this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface'); - $this->io = $this->getMockBuilder('Composer\IO\IOInterface') - ->getMock(); + $this->io = $this->getMock('Composer\IO\IOInterface'); } public function testInstallNewInstaller() @@ -47,7 +45,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase ->expects($this->once()) ->method('getPackages') ->will($this->returnValue(array())); - $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->repository, $this->io, $this->im); + $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->io, $this->im, array($this->repository)); $test = $this; $this->im @@ -57,7 +55,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase $test->assertEquals('installer-v1', $installer->version); })); - $installer->install($this->packages[0]); + $installer->install($this->repository, $this->packages[0]); } public function testUpgradeWithNewClassName() @@ -70,7 +68,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase ->expects($this->exactly(2)) ->method('hasPackage') ->will($this->onConsecutiveCalls(true, false)); - $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->repository, $this->io, $this->im); + $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->io, $this->im, array($this->repository)); $test = $this; $this->im @@ -80,7 +78,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase $test->assertEquals('installer-v2', $installer->version); })); - $installer->update($this->packages[0], $this->packages[1]); + $installer->update($this->repository, $this->packages[0], $this->packages[1]); } public function testUpgradeWithSameClassName() @@ -93,7 +91,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase ->expects($this->exactly(2)) ->method('hasPackage') ->will($this->onConsecutiveCalls(true, false)); - $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->repository, $this->io, $this->im); + $installer = new InstallerInstallerMock(__DIR__.'/Fixtures/', __DIR__.'/Fixtures/bin', $this->dm, $this->io, $this->im, array($this->repository)); $test = $this; $this->im @@ -103,7 +101,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase $test->assertEquals('installer-v3', $installer->version); })); - $installer->update($this->packages[1], $this->packages[2]); + $installer->update($this->repository, $this->packages[1], $this->packages[2]); } } diff --git a/tests/Composer/Test/Installer/LibraryInstallerTest.php b/tests/Composer/Test/Installer/LibraryInstallerTest.php index 100ebb60e..7983cf2a2 100644 --- a/tests/Composer/Test/Installer/LibraryInstallerTest.php +++ b/tests/Composer/Test/Installer/LibraryInstallerTest.php @@ -40,11 +40,9 @@ class LibraryInstallerTest extends TestCase ->disableOriginalConstructor() ->getMock(); - $this->repository = $this->getMockBuilder('Composer\Repository\WritableRepositoryInterface') - ->getMock(); + $this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface'); - $this->io = $this->getMockBuilder('Composer\IO\IOInterface') - ->getMock(); + $this->io = $this->getMock('Composer\IO\IOInterface'); } protected function tearDown() @@ -57,7 +55,7 @@ class LibraryInstallerTest extends TestCase { $this->fs->removeDirectory($this->vendorDir); - new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $this->assertFileNotExists($this->vendorDir); } @@ -65,13 +63,13 @@ class LibraryInstallerTest extends TestCase { $this->fs->removeDirectory($this->binDir); - new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $this->assertFileNotExists($this->binDir); } public function testIsInstalled() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $package = $this->createPackageMock(); $this->repository @@ -80,8 +78,8 @@ class LibraryInstallerTest extends TestCase ->with($package) ->will($this->onConsecutiveCalls(true, false)); - $this->assertTrue($library->isInstalled($package)); - $this->assertFalse($library->isInstalled($package)); + $this->assertTrue($library->isInstalled($this->repository, $package)); + $this->assertFalse($library->isInstalled($this->repository, $package)); } /** @@ -90,7 +88,7 @@ class LibraryInstallerTest extends TestCase */ public function testInstall() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $package = $this->createPackageMock(); $package @@ -108,7 +106,7 @@ class LibraryInstallerTest extends TestCase ->method('addPackage') ->with($package); - $library->install($package); + $library->install($this->repository, $package); $this->assertFileExists($this->vendorDir, 'Vendor dir should be created'); $this->assertFileExists($this->binDir, 'Bin dir should be created'); } @@ -119,7 +117,7 @@ class LibraryInstallerTest extends TestCase */ public function testUpdate() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $initial = $this->createPackageMock(); $target = $this->createPackageMock(); @@ -148,18 +146,18 @@ class LibraryInstallerTest extends TestCase ->method('addPackage') ->with($target); - $library->update($initial, $target); + $library->update($this->repository, $initial, $target); $this->assertFileExists($this->vendorDir, 'Vendor dir should be created'); $this->assertFileExists($this->binDir, 'Bin dir should be created'); $this->setExpectedException('InvalidArgumentException'); - $library->update($initial, $target); + $library->update($this->repository, $initial, $target); } public function testUninstall() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $package = $this->createPackageMock(); $package @@ -183,17 +181,17 @@ class LibraryInstallerTest extends TestCase ->method('removePackage') ->with($package); - $library->uninstall($package); + $library->uninstall($this->repository, $package); // TODO re-enable once #125 is fixed and we throw exceptions again // $this->setExpectedException('InvalidArgumentException'); - $library->uninstall($package); + $library->uninstall($this->repository, $package); } public function testGetInstallPath() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $package = $this->createPackageMock(); $package @@ -206,7 +204,7 @@ class LibraryInstallerTest extends TestCase public function testGetInstallPathWithTargetDir() { - $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->io); $package = $this->createPackageMock(); $package diff --git a/tests/Composer/Test/Installer/MetapackageInstallerTest.php b/tests/Composer/Test/Installer/MetapackageInstallerTest.php index fd71eb1b6..45d1ff605 100644 --- a/tests/Composer/Test/Installer/MetapackageInstallerTest.php +++ b/tests/Composer/Test/Installer/MetapackageInstallerTest.php @@ -26,7 +26,7 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase $this->io = $this->getMock('Composer\IO\IOInterface'); - $this->installer = new MetapackageInstaller($this->repository, $this->io); + $this->installer = new MetapackageInstaller(); } public function testInstall() @@ -38,7 +38,7 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase ->method('addPackage') ->with($package); - $this->installer->install($package); + $this->installer->install($this->repository, $package); } public function testUpdate() @@ -62,11 +62,11 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase ->method('addPackage') ->with($target); - $this->installer->update($initial, $target); + $this->installer->update($this->repository, $initial, $target); $this->setExpectedException('InvalidArgumentException'); - $this->installer->update($initial, $target); + $this->installer->update($this->repository, $initial, $target); } public function testUninstall() @@ -84,12 +84,12 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase ->method('removePackage') ->with($package); - $this->installer->uninstall($package); + $this->installer->uninstall($this->repository, $package); // TODO re-enable once #125 is fixed and we throw exceptions again // $this->setExpectedException('InvalidArgumentException'); - $this->installer->uninstall($package); + $this->installer->uninstall($this->repository, $package); } private function createPackageMock() diff --git a/tests/Composer/Test/Package/LockerTest.php b/tests/Composer/Test/Package/LockerTest.php index 9c3f3cbe0..a4cbb6e1d 100644 --- a/tests/Composer/Test/Package/LockerTest.php +++ b/tests/Composer/Test/Package/LockerTest.php @@ -151,10 +151,11 @@ class LockerTest extends \PHPUnit_Framework_TestCase array('package' => 'pkg1', 'version' => '1.0.0-beta'), array('package' => 'pkg2', 'version' => '0.1.10') ), + 'packages-dev' => array(), 'aliases' => array(), )); - $locker->setLockData(array($package1, $package2), array()); + $locker->setLockData(array($package1, $package2), array(), array()); } public function testLockBadPackages() @@ -172,7 +173,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase $this->setExpectedException('LogicException'); - $locker->setLockData(array($package1), array()); + $locker->setLockData(array($package1), array(), array()); } public function testIsFresh() From 8d4f8543fccfdd85a3fa1773a5768ee8b1c411e2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 23:52:52 +0200 Subject: [PATCH 8/9] Update docs --- doc/03-cli.md | 15 ++++++--------- doc/04-schema.md | 27 ++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 855fca837..4648aa42a 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -39,11 +39,9 @@ resolution. * **--dry-run:** If you want to run through an installation without actually installing a package, you can use `--dry-run`. This will simulate the installation and show you what would happen. -* **--no-install-recommends:** By default composer will install all packages - that are referenced by `recommend`. By passing this option you can disable - that. -* **--install-suggests:** The packages referenced by `suggest` will not be - installed by default. By passing this option, you can install them. +* **--dev:** By default composer will only install required packages. By + passing this option you can also make it install packages referenced by + `require-dev`. ## update @@ -59,8 +57,7 @@ into `composer.lock`. * **--prefer-source:** Install packages from `source` when available. * **--dry-run:** Simulate the command without actually doing anything. -* **--no-install-recommends:** Do not install packages referenced by `recommend`. -* **--install-suggests:** Install packages referenced by `suggest`. +* **--dev:** Install packages listed in `require-dev`. ## search @@ -111,8 +108,8 @@ specific version. ## depends The `depends` command tells you which other packages depend on a certain -package. You can specify which link types (`require`, `recommend`, `suggest`) -should be included in the listing. +package. You can specify which link types (`require`, `require-dev`) +should be included in the listing. By default both are used. $ php composer.phar depends --link-type=require monolog/monolog diff --git a/doc/04-schema.md b/doc/04-schema.md index 5886608e6..2b7aef879 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -41,7 +41,7 @@ Required for published packages (libraries). A short description of the package. Usually this is just one line long. -Optional but recommended. +Required for published packages (libraries). ### version @@ -165,14 +165,13 @@ An example: Optional, but highly recommended. -### Link types (require, recommend, suggest, replace, provide) +### Package links (require, require-dev, conflict, replace, provide) Each of these takes an object which maps package names to version constraints. * **require:** Packages required by this package. -* **recommend:** Recommended packages, installed by default. -* **suggest:** Suggested packages. These are displayed after installation, - but not installed by default. +* **require-dev:** Packages required for developing this package, or running + tests, etc. They are installed if install or update is ran with `--dev`. * **conflict:** Mark this version of this package as conflicting with other packages. * **replace:** Packages that can be replaced by this package. This is useful @@ -193,6 +192,24 @@ Example: Optional. +### suggest + +Suggested packages that can enhance or work well with this package. These are +just informational and are displayed after the package is installed, to give +your users a hint that they could add more packages, even though they are not +strictly required. + +The format is like package links above, except that the values are free text +and not version constraints. + +Example: + + { + "suggest": { + "monolog/monolog": "Allows more advanced logging of the application flow" + } + } + ### autoload Autoload mapping for a PHP autoloader. From d1f66073ca1a0a399c813fdff4210b5f88bc8e68 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 14 Apr 2012 23:53:12 +0200 Subject: [PATCH 9/9] Update depends command --- src/Composer/Command/DependsCommand.php | 13 ++++++++----- .../Test/Installer/InstallationManagerTest.php | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php index 82ff5e02d..5c06e96f5 100644 --- a/src/Composer/Command/DependsCommand.php +++ b/src/Composer/Command/DependsCommand.php @@ -25,7 +25,10 @@ use Symfony\Component\Console\Output\OutputInterface; */ class DependsCommand extends Command { - protected $linkTypes = array('require', 'recommend', 'suggest'); + protected $linkTypes = array( + 'require' => 'requires', + 'require-dev' => 'devRequires', + ); protected function configure() { @@ -34,7 +37,7 @@ class DependsCommand extends Command ->setDescription('Shows which packages depend on the given package') ->setDefinition(array( new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'), - new InputOption('link-type', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Link types to show', $this->linkTypes) + new InputOption('link-type', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Link types to show (require, require-dev)', array_keys($this->linkTypes)) )) ->setHelp(<<getPackages() as $package) { foreach ($types as $type) { $type = rtrim($type, 's'); - if (!in_array($type, $this->linkTypes)) { - throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', $this->linkTypes)); + if (!isset($this->linkTypes[$type])) { + throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', array_keys($this->linkTypes))); } - foreach ($package->{'get'.$type.'s'}() as $link) { + foreach ($package->{'get'.$this->linkTypes[$type]}() as $link) { if ($link->getTarget() === $needle) { if ($verbose) { $references[] = array($type, $package, $link); diff --git a/tests/Composer/Test/Installer/InstallationManagerTest.php b/tests/Composer/Test/Installer/InstallationManagerTest.php index f14c08c84..a657ba948 100644 --- a/tests/Composer/Test/Installer/InstallationManagerTest.php +++ b/tests/Composer/Test/Installer/InstallationManagerTest.php @@ -72,7 +72,6 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $this->createPackageMock(), $this->createPackageMock() ); - $manager ->expects($this->once()) ->method('install')