1
0
Fork 0

Merge pull request #575 from Seldaek/newlinks

New link handling, removed recommend, added require-dev, and changed suggest
pull/582/head
Nils Adermann 2012-04-14 17:40:02 -07:00
commit 65999c48e1
35 changed files with 571 additions and 347 deletions

View File

@ -1,5 +1,8 @@
* 1.0.0-alpha3 * 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 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 include_path support for legacy projects that are full of require_once statements
* Added installation notifications API to allow better statistics on Composer repositories * Added installation notifications API to allow better statistics on Composer repositories

View File

@ -25,8 +25,8 @@
"symfony/finder": "2.1.*", "symfony/finder": "2.1.*",
"symfony/process": "2.1.*" "symfony/process": "2.1.*"
}, },
"recommend": { "suggest": {
"ext-zip": "*" "ext-zip": "Enabling the zip extension allows you to zip archives, and allows gzip compression of all internet traffic"
}, },
"autoload": { "autoload": {
"psr-0": { "Composer": "src/" } "psr-0": { "Composer": "src/" }

View File

@ -39,11 +39,9 @@ resolution.
* **--dry-run:** If you want to run through an installation without actually * **--dry-run:** If you want to run through an installation without actually
installing a package, you can use `--dry-run`. This will simulate the installing a package, you can use `--dry-run`. This will simulate the
installation and show you what would happen. installation and show you what would happen.
* **--no-install-recommends:** By default composer will install all packages * **--dev:** By default composer will only install required packages. By
that are referenced by `recommend`. By passing this option you can disable passing this option you can also make it install packages referenced by
that. `require-dev`.
* **--install-suggests:** The packages referenced by `suggest` will not be
installed by default. By passing this option, you can install them.
## update ## update
@ -59,8 +57,7 @@ into `composer.lock`.
* **--prefer-source:** Install packages from `source` when available. * **--prefer-source:** Install packages from `source` when available.
* **--dry-run:** Simulate the command without actually doing anything. * **--dry-run:** Simulate the command without actually doing anything.
* **--no-install-recommends:** Do not install packages referenced by `recommend`. * **--dev:** Install packages listed in `require-dev`.
* **--install-suggests:** Install packages referenced by `suggest`.
## search ## search
@ -111,8 +108,8 @@ specific version.
## depends ## depends
The `depends` command tells you which other packages depend on a certain The `depends` command tells you which other packages depend on a certain
package. You can specify which link types (`require`, `recommend`, `suggest`) package. You can specify which link types (`require`, `require-dev`)
should be included in the listing. should be included in the listing. By default both are used.
$ php composer.phar depends --link-type=require monolog/monolog $ php composer.phar depends --link-type=require monolog/monolog

View File

@ -41,7 +41,7 @@ Required for published packages (libraries).
A short description of the package. Usually this is just one line long. A short description of the package. Usually this is just one line long.
Optional but recommended. Required for published packages (libraries).
### version ### version
@ -165,14 +165,13 @@ An example:
Optional, but highly recommended. Optional, but highly recommended.
### Link types <span>(require, recommend, suggest, replace, provide)</span> ### Package links <span>(require, require-dev, conflict, replace, provide)</span>
Each of these takes an object which maps package names to version constraints. Each of these takes an object which maps package names to version constraints.
* **require:** Packages required by this package. * **require:** Packages required by this package.
* **recommend:** Recommended packages, installed by default. * **require-dev:** Packages required for developing this package, or running
* **suggest:** Suggested packages. These are displayed after installation, tests, etc. They are installed if install or update is ran with `--dev`.
but not installed by default.
* **conflict:** Mark this version of this package as conflicting with other * **conflict:** Mark this version of this package as conflicting with other
packages. packages.
* **replace:** Packages that can be replaced by this package. This is useful * **replace:** Packages that can be replaced by this package. This is useful
@ -193,6 +192,24 @@ Example:
Optional. 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
Autoload mapping for a PHP autoloader. Autoload mapping for a PHP autoloader.

View File

@ -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.", "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 "additionalProperties": true
}, },
"recommend": { "require-dev": {
"type": "object", "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 "additionalProperties": true
}, },
"suggest": { "suggest": {
"type": "object", "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 "additionalProperties": true
}, },
"config": { "config": {

View File

@ -25,7 +25,10 @@ use Symfony\Component\Console\Output\OutputInterface;
*/ */
class DependsCommand extends Command class DependsCommand extends Command
{ {
protected $linkTypes = array('require', 'recommend', 'suggest'); protected $linkTypes = array(
'require' => 'requires',
'require-dev' => 'devRequires',
);
protected function configure() protected function configure()
{ {
@ -34,7 +37,7 @@ class DependsCommand extends Command
->setDescription('Shows which packages depend on the given package') ->setDescription('Shows which packages depend on the given package')
->setDefinition(array( ->setDefinition(array(
new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'), 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(<<<EOT ->setHelp(<<<EOT
Displays detailed information about where a package is referenced. Displays detailed information about where a package is referenced.
@ -81,10 +84,10 @@ EOT
foreach ($repository->getPackages() as $package) { foreach ($repository->getPackages() as $package) {
foreach ($types as $type) { foreach ($types as $type) {
$type = rtrim($type, 's'); $type = rtrim($type, 's');
if (!in_array($type, $this->linkTypes)) { if (!isset($this->linkTypes[$type])) {
throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', $this->linkTypes)); 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 ($link->getTarget() === $needle) {
if ($verbose) { if ($verbose) {
$references[] = array($type, $package, $link); $references[] = array($type, $package, $link);

View File

@ -32,8 +32,7 @@ class InstallCommand extends Command
->setDefinition(array( ->setDefinition(array(
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), 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('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('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'),
new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages (ignored when installing from an existing lock file).'),
)) ))
->setHelp(<<<EOT ->setHelp(<<<EOT
The <info>install</info> command reads the composer.json file from the The <info>install</info> command reads the composer.json file from the
@ -57,8 +56,7 @@ EOT
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
->setPreferSource($input->getOption('prefer-source')) ->setPreferSource($input->getOption('prefer-source'))
->setInstallRecommends(!$input->getOption('no-install-recommends')) ->setDevMode($input->getOption('dev'))
->setInstallSuggests($input->getOption('install-suggests'))
; ;
return $install->run() ? 0 : 1; return $install->run() ? 0 : 1;

View File

@ -30,8 +30,7 @@ class UpdateCommand extends Command
->setDefinition(array( ->setDefinition(array(
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), 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('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('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'),
new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages.'),
)) ))
->setHelp(<<<EOT ->setHelp(<<<EOT
The <info>update</info> command reads the composer.json file from the The <info>update</info> command reads the composer.json file from the
@ -55,11 +54,10 @@ EOT
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
->setPreferSource($input->getOption('prefer-source')) ->setPreferSource($input->getOption('prefer-source'))
->setInstallRecommends(!$input->getOption('no-install-recommends')) ->setDevMode($input->getOption('dev'))
->setInstallSuggests($input->getOption('install-suggests'))
->setUpdate(true) ->setUpdate(true)
; ;
return $install->run(); return $install->run() ? 0 : 1;
} }
} }

View File

@ -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);
}
}
} }
} }

View File

@ -152,6 +152,7 @@ class Factory
protected function addLocalRepository(RepositoryManager $rm, $vendorDir) protected function addLocalRepository(RepositoryManager $rm, $vendorDir)
{ {
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
$rm->setLocalDevRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed_dev.json')));
} }
protected function addPackagistRepository(array $localConfig) protected function addPackagistRepository(array $localConfig)
@ -202,18 +203,20 @@ class Factory
protected function createInstallationManager(Repository\RepositoryManager $rm, Downloader\DownloadManager $dm, $vendorDir, $binDir, IOInterface $io) protected function createInstallationManager(Repository\RepositoryManager $rm, Downloader\DownloadManager $dm, $vendorDir, $binDir, IOInterface $io)
{ {
$im = new Installer\InstallationManager($vendorDir); $im = new Installer\InstallationManager($vendorDir);
$im->addInstaller(new Installer\LibraryInstaller($vendorDir, $binDir, $dm, $rm->getLocalRepository(), $io, null)); $im->addInstaller(new Installer\LibraryInstaller($vendorDir, $binDir, $dm, $io, null));
$im->addInstaller(new Installer\InstallerInstaller($vendorDir, $binDir, $dm, $rm->getLocalRepository(), $io, $im)); $im->addInstaller(new Installer\InstallerInstaller($vendorDir, $binDir, $dm, $io, $im, $rm->getLocalRepositories()));
$im->addInstaller(new Installer\MetapackageInstaller($rm->getLocalRepository(), $io)); $im->addInstaller(new Installer\MetapackageInstaller($io));
return $im; return $im;
} }
protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im) protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im)
{ {
foreach ($rm->getLocalRepository()->getPackages() as $package) { foreach ($rm->getLocalRepositories() as $repo) {
if (!$im->isPackageInstalled($package)) { foreach ($repo->getPackages() as $package) {
$rm->getLocalRepository()->removePackage($package); if (!$im->isPackageInstalled($repo, $package)) {
$repo->removePackage($package);
}
} }
} }
} }

View File

@ -77,10 +77,9 @@ class Installer
protected $eventDispatcher; protected $eventDispatcher;
protected $preferSource = false; protected $preferSource = false;
protected $devMode = false;
protected $dryRun = false; protected $dryRun = false;
protected $verbose = false; protected $verbose = false;
protected $installRecommends = true;
protected $installSuggests = false;
protected $update = false; protected $update = false;
/** /**
@ -123,33 +122,14 @@ class Installer
$this->downloadManager->setPreferSource(true); $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) // 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) { if ($this->additionalInstalledRepository) {
$installedRepo->addRepository($this->additionalInstalledRepository); $installedRepo->addRepository($this->additionalInstalledRepository);
} }
// prepare aliased packages $aliases = $this->aliasPackages();
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);
}
}
// creating repository pool // creating repository pool
$pool = new Pool; $pool = new Pool;
@ -158,34 +138,74 @@ class Installer
$pool->addRepository($repository); $pool->addRepository($repository);
} }
// dispatch pre event
if (!$this->dryRun) { if (!$this->dryRun) {
// dispatch pre event
$eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
$this->eventDispatcher->dispatchCommandEvent($eventName); $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('<info>Writing lock file</info>');
}
}
// write autoloader
$this->io->write('<info>Generating autoload files</info>');
$generator = new AutoloadGenerator;
$localRepos = new CompositeRepository($this->repositoryManager->getLocalRepositories());
$generator->dump($localRepos, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer');
// 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 // creating requirements request
$installFromLock = false; $installFromLock = false;
$request = new Request($pool); $request = new Request($pool);
if ($this->update) { if ($this->update) {
$this->io->write('Updating dependencies'); $this->io->write('<info>Updating '.($devMode ? 'dev ': '').'dependencies</info>');
$request->updateAll(); $request->updateAll();
$links = $this->collectLinks(); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires();
foreach ($links as $link) { foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint()); $request->install($link->getTarget(), $link->getConstraint());
} }
} elseif ($this->locker->isLocked()) { } elseif ($this->locker->isLocked()) {
$installFromLock = true; $installFromLock = true;
$this->io->write('Installing from lock file'); $this->io->write('<info>Installing '.($devMode ? 'dev ': '').'dependencies from lock file</info>');
if (!$this->locker->isFresh()) { if (!$this->locker->isFresh() && !$devMode) {
$this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>'); $this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>');
} }
foreach ($this->locker->getLockedPackages() as $package) { foreach ($this->locker->getLockedPackages($devMode) as $package) {
$version = $package->getVersion(); $version = $package->getVersion();
foreach ($aliases as $alias) { foreach ($aliases as $alias) {
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) { if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
@ -197,15 +217,25 @@ class Installer
$request->install($package->getName(), $constraint); $request->install($package->getName(), $constraint);
} }
} else { } else {
$this->io->write('Installing dependencies'); $this->io->write('<info>Installing '.($devMode ? 'dev ': '').'dependencies</info>');
$links = $this->collectLinks(); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires();
foreach ($links as $link) { foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint()); $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 // prepare solver
$policy = new DefaultPolicy(); $policy = new DefaultPolicy();
$solver = new Solver($policy, $pool, $installedRepo); $solver = new Solver($policy, $pool, $installedRepo);
@ -262,22 +292,35 @@ class Installer
} }
// anti-alias local repository to allow updates to work fine // 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) { if ($package instanceof AliasPackage) {
$this->repositoryManager->getLocalRepository()->addPackage(clone $package->getAliasOf()); $package->getRepository()->addPackage(clone $package->getAliasOf());
$this->repositoryManager->getLocalRepository()->removePackage($package); $package->getRepository()->removePackage($package);
} }
} }
// execute operations // execute operations
if (!$operations) { if (!$operations) {
$this->io->write('<info>Nothing to install or update</info>'); $this->io->write('Nothing to install or update');
} }
$suggestedPackages = array();
foreach ($operations as $operation) { foreach ($operations as $operation) {
if ($this->verbose) { if ($this->verbose) {
$this->io->write((string) $operation); $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) { if (!$this->dryRun) {
$this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation); $this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
@ -299,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); $this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
@ -307,40 +350,34 @@ class Installer
} }
} }
if (!$this->dryRun) { return $suggestedPackages;
if ($this->update || !$this->locker->isLocked()) {
if ($this->locker->setLockData($localRepo->getPackages(), $aliases)) {
$this->io->write('<info>Writing lock file</info>');
}
} }
$localRepo->write(); private function aliasPackages()
$this->io->write('<info>Generating autoload files</info>');
$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(); if (!$this->update && $this->locker->isLocked()) {
$aliases = $this->locker->getAliases();
if ($this->installRecommends) { } else {
$links = array_merge($links, $this->package->getRecommends()); $aliases = $this->package->getAliases();
} }
if ($this->installSuggests) { foreach ($aliases as $alias) {
$links = array_merge($links, $this->package->getSuggests()); 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);
}
}
} }
return $links; return $aliases;
} }
/** /**
@ -386,32 +423,6 @@ class Installer
return $this; return $this;
} }
/**
* install recommend packages
*
* @param boolean $noInstallRecommends
* @return Installer
*/
public function setInstallRecommends($installRecommends=true)
{
$this->installRecommends = (boolean) $installRecommends;
return $this;
}
/**
* also install suggested packages
*
* @param boolean $installSuggests
* @return Installer
*/
public function setInstallSuggests($installSuggests=true)
{
$this->installSuggests = (boolean) $installSuggests;
return $this;
}
/** /**
* prefer source installation * prefer source installation
* *
@ -438,6 +449,19 @@ class Installer
return $this; return $this;
} }
/**
* enables dev packages
*
* @param boolean $update
* @return Installer
*/
public function setDevMode($devMode = true)
{
$this->devMode = (boolean) $devMode;
return $this;
}
/** /**
* run in verbose mode * run in verbose mode
* *

View File

@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\NotifiableRepositoryInterface; use Composer\Repository\NotifiableRepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\InstallOperation; use Composer\DependencyResolver\Operation\InstallOperation;
@ -95,32 +96,35 @@ class InstallationManager
/** /**
* Checks whether provided package is installed in one of the registered installers. * 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 * @param PackageInterface $package package instance
* *
* @return Boolean * @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. * Executes solver operation.
* *
* @param RepositoryInterface $repo repository in which to check
* @param OperationInterface $operation operation instance * @param OperationInterface $operation operation instance
*/ */
public function execute(OperationInterface $operation) public function execute(RepositoryInterface $repo, OperationInterface $operation)
{ {
$method = $operation->getJobType(); $method = $operation->getJobType();
$this->$method($operation); $this->$method($repo, $operation);
} }
/** /**
* Executes install operation. * Executes install operation.
* *
* @param RepositoryInterface $repo repository in which to check
* @param InstallOperation $operation operation instance * @param InstallOperation $operation operation instance
*/ */
public function install(InstallOperation $operation) public function install(RepositoryInterface $repo, InstallOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
if ($package instanceof AliasPackage) { if ($package instanceof AliasPackage) {
@ -128,16 +132,17 @@ class InstallationManager
$package->setInstalledAsAlias(true); $package->setInstalledAsAlias(true);
} }
$installer = $this->getInstaller($package->getType()); $installer = $this->getInstaller($package->getType());
$installer->install($package); $installer->install($repo, $package);
$this->notifyInstall($package); $this->notifyInstall($package);
} }
/** /**
* Executes update operation. * Executes update operation.
* *
* @param RepositoryInterface $repo repository in which to check
* @param InstallOperation $operation operation instance * @param InstallOperation $operation operation instance
*/ */
public function update(UpdateOperation $operation) public function update(RepositoryInterface $repo, UpdateOperation $operation)
{ {
$initial = $operation->getInitialPackage(); $initial = $operation->getInitialPackage();
if ($initial instanceof AliasPackage) { if ($initial instanceof AliasPackage) {
@ -154,27 +159,28 @@ class InstallationManager
if ($initialType === $targetType) { if ($initialType === $targetType) {
$installer = $this->getInstaller($initialType); $installer = $this->getInstaller($initialType);
$installer->update($initial, $target); $installer->update($repo, $initial, $target);
$this->notifyInstall($target); $this->notifyInstall($target);
} else { } else {
$this->getInstaller($initialType)->uninstall($initial); $this->getInstaller($initialType)->uninstall($repo, $initial);
$this->getInstaller($targetType)->install($target); $this->getInstaller($targetType)->install($repo, $target);
} }
} }
/** /**
* Uninstalls package. * Uninstalls package.
* *
* @param RepositoryInterface $repo repository in which to check
* @param UninstallOperation $operation operation instance * @param UninstallOperation $operation operation instance
*/ */
public function uninstall(UninstallOperation $operation) public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
if ($package instanceof AliasPackage) { if ($package instanceof AliasPackage) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();
} }
$installer = $this->getInstaller($package->getType()); $installer = $this->getInstaller($package->getType());
$installer->uninstall($package); $installer->uninstall($repo, $package);
} }
/** /**

View File

@ -33,46 +33,49 @@ class InstallerInstaller extends LibraryInstaller
* @param string $vendorDir relative path for packages home * @param string $vendorDir relative path for packages home
* @param string $binDir relative path for binaries * @param string $binDir relative path for binaries
* @param DownloadManager $dm download manager * @param DownloadManager $dm download manager
* @param WritableRepositoryInterface $repository repository controller
* @param IOInterface $io io instance * @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; $this->installationManager = $im;
foreach ($repository->getPackages() as $package) { foreach ($localRepositories as $repo) {
foreach ($repo->getPackages() as $package) {
if ('composer-installer' === $package->getType()) { if ('composer-installer' === $package->getType()) {
$this->registerInstaller($package); $this->registerInstaller($package);
} }
} }
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function install(PackageInterface $package) public function install(WritableRepositoryInterface $repo, PackageInterface $package)
{ {
$extra = $package->getExtra(); $extra = $package->getExtra();
if (empty($extra['class'])) { 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.'); 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); $this->registerInstaller($package);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function update(PackageInterface $initial, PackageInterface $target) public function update(WritableRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{ {
$extra = $target->getExtra(); $extra = $target->getExtra();
if (empty($extra['class'])) { 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.'); 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); $this->registerInstaller($target);
} }
@ -97,7 +100,7 @@ class InstallerInstaller extends LibraryInstaller
} }
$extra = $package->getExtra(); $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); $this->installationManager->addInstaller($installer);
} }
} }

View File

@ -14,11 +14,13 @@ namespace Composer\Installer;
use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Repository\WritableRepositoryInterface;
/** /**
* Interface for the package installation manager. * Interface for the package installation manager.
* *
* @author Konstantin Kudryashov <ever.zet@gmail.com> * @author Konstantin Kudryashov <ever.zet@gmail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
interface InstallerInterface interface InstallerInterface
{ {
@ -33,35 +35,39 @@ interface InstallerInterface
/** /**
* Checks that provided package is installed. * Checks that provided package is installed.
* *
* @param WritableRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance * @param PackageInterface $package package instance
* *
* @return Boolean * @return Boolean
*/ */
function isInstalled(PackageInterface $package); function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package);
/** /**
* Installs specific package. * Installs specific package.
* *
* @param WritableRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance * @param PackageInterface $package package instance
*/ */
function install(PackageInterface $package); function install(WritableRepositoryInterface $repo, PackageInterface $package);
/** /**
* Updates specific package. * Updates specific package.
* *
* @param WritableRepositoryInterface $repo repository in which to check
* @param PackageInterface $initial already installed package version * @param PackageInterface $initial already installed package version
* @param PackageInterface $target updated version * @param PackageInterface $target updated version
* *
* @throws InvalidArgumentException if $from package is not installed * @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. * Uninstalls specific package.
* *
* @param WritableRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance * @param PackageInterface $package package instance
*/ */
function uninstall(PackageInterface $package); function uninstall(WritableRepositoryInterface $repo, PackageInterface $package);
/** /**
* Returns the installation path of a package * Returns the installation path of a package

View File

@ -30,7 +30,6 @@ class LibraryInstaller implements InstallerInterface
protected $vendorDir; protected $vendorDir;
protected $binDir; protected $binDir;
protected $downloadManager; protected $downloadManager;
protected $repository;
protected $io; protected $io;
private $type; private $type;
private $filesystem; private $filesystem;
@ -41,14 +40,12 @@ class LibraryInstaller implements InstallerInterface
* @param string $vendorDir relative path for packages home * @param string $vendorDir relative path for packages home
* @param string $binDir relative path for binaries * @param string $binDir relative path for binaries
* @param DownloadManager $dm download manager * @param DownloadManager $dm download manager
* @param WritableRepositoryInterface $repository repository controller
* @param IOInterface $io io instance * @param IOInterface $io io instance
* @param string $type package type that this installer handles * @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->downloadManager = $dm;
$this->repository = $repository;
$this->io = $io; $this->io = $io;
$this->type = $type; $this->type = $type;
@ -68,37 +65,37 @@ class LibraryInstaller implements InstallerInterface
/** /**
* {@inheritDoc} * {@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} * {@inheritDoc}
*/ */
public function install(PackageInterface $package) public function install(WritableRepositoryInterface $repo, PackageInterface $package)
{ {
$this->initializeVendorDir(); $this->initializeVendorDir();
$downloadPath = $this->getInstallPath($package); $downloadPath = $this->getInstallPath($package);
// remove the binaries if it appears the package files are missing // 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->removeBinaries($package);
} }
$this->downloadManager->download($package, $downloadPath); $this->downloadManager->download($package, $downloadPath);
$this->installBinaries($package); $this->installBinaries($package);
if (!$this->repository->hasPackage($package)) { if (!$repo->hasPackage($package)) {
$this->repository->addPackage(clone $package); $repo->addPackage(clone $package);
} }
} }
/** /**
* {@inheritDoc} * {@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); throw new \InvalidArgumentException('Package is not installed: '.$initial);
} }
@ -108,18 +105,18 @@ class LibraryInstaller implements InstallerInterface
$this->removeBinaries($initial); $this->removeBinaries($initial);
$this->downloadManager->update($initial, $target, $downloadPath); $this->downloadManager->update($initial, $target, $downloadPath);
$this->installBinaries($target); $this->installBinaries($target);
$this->repository->removePackage($initial); $repo->removePackage($initial);
if (!$this->repository->hasPackage($target)) { if (!$repo->hasPackage($target)) {
$this->repository->addPackage(clone $target); $repo->addPackage(clone $target);
} }
} }
/** /**
* {@inheritDoc} * {@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) // TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125)
return; return;
throw new \InvalidArgumentException('Package is not installed: '.$package); throw new \InvalidArgumentException('Package is not installed: '.$package);
@ -129,7 +126,7 @@ class LibraryInstaller implements InstallerInterface
$this->downloadManager->remove($package, $downloadPath); $this->downloadManager->remove($package, $downloadPath);
$this->removeBinaries($package); $this->removeBinaries($package);
$this->repository->removePackage($package); $repo->removePackage($package);
} }
/** /**
@ -138,6 +135,7 @@ class LibraryInstaller implements InstallerInterface
public function getInstallPath(PackageInterface $package) public function getInstallPath(PackageInterface $package)
{ {
$targetDir = $package->getTargetDir(); $targetDir = $package->getTargetDir();
return ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName() . ($targetDir ? '/'.$targetDir : ''); return ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName() . ($targetDir ? '/'.$targetDir : '');
} }

View File

@ -12,7 +12,6 @@
namespace Composer\Installer; namespace Composer\Installer;
use Composer\IO\IOInterface;
use Composer\Repository\WritableRepositoryInterface; use Composer\Repository\WritableRepositoryInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
@ -23,19 +22,6 @@ use Composer\Package\PackageInterface;
*/ */
class MetapackageInstaller implements InstallerInterface 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} * {@inheritDoc}
*/ */
@ -47,44 +33,44 @@ class MetapackageInstaller implements InstallerInterface
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function isInstalled(PackageInterface $package) public function isInstalled(WritableRepositoryInterface $repo, PackageInterface $package)
{ {
return $this->repository->hasPackage($package); return $repo->hasPackage($package);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function install(PackageInterface $package) public function install(WritableRepositoryInterface $repo, PackageInterface $package)
{ {
$this->repository->addPackage(clone $package); $repo->addPackage(clone $package);
} }
/** /**
* {@inheritDoc} * {@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); throw new \InvalidArgumentException('Package is not installed: '.$initial);
} }
$this->repository->removePackage($initial); $repo->removePackage($initial);
$this->repository->addPackage(clone $target); $repo->addPackage(clone $target);
} }
/** /**
* {@inheritDoc} * {@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) // TODO throw exception again here, when update is fixed and we don't have to remove+install (see #125)
return; return;
throw new \InvalidArgumentException('Package is not installed: '.$package); throw new \InvalidArgumentException('Package is not installed: '.$package);
} }
$this->repository->removePackage($package); $repo->removePackage($package);
} }
/** /**

View File

@ -52,7 +52,7 @@ class AliasPackage extends BasePackage
$this->dev = VersionParser::isDev($version); $this->dev = VersionParser::isDev($version);
// replace self.version dependencies // replace self.version dependencies
foreach (array('requires', 'recommends', 'suggests') as $type) { foreach (array('requires', 'devRequires') as $type) {
$links = $aliasOf->{'get'.ucfirst($type)}(); $links = $aliasOf->{'get'.ucfirst($type)}();
foreach ($links as $index => $link) { foreach ($links as $index => $link) {
// link is self.version, but must be replacing also the replaced version // link is self.version, but must be replacing also the replaced version
@ -141,17 +141,9 @@ class AliasPackage extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getRecommends() public function getDevRequires()
{ {
return $this->recommends; return $this->devRequires;
}
/**
* {@inheritDoc}
*/
public function getSuggests()
{
return $this->suggests;
} }
/** /**
@ -266,6 +258,10 @@ class AliasPackage extends BasePackage
{ {
return $this->aliasOf->getHomepage(); return $this->aliasOf->getHomepage();
} }
public function getSuggests()
{
return $this->aliasOf->getSuggests();
}
public function getAuthors() public function getAuthors()
{ {
return $this->aliasOf->getAuthors(); return $this->aliasOf->getAuthors();

View File

@ -25,12 +25,11 @@ use Composer\Repository\PlatformRepository;
abstract class BasePackage implements PackageInterface abstract class BasePackage implements PackageInterface
{ {
public static $supportedLinkTypes = array( public static $supportedLinkTypes = array(
'require' => 'requires', 'require' => array('description' => 'requires', 'method' => 'requires'),
'conflict' => 'conflicts', 'conflict' => array('description' => 'conflicts', 'method' => 'conflicts'),
'provide' => 'provides', 'provide' => array('description' => 'provides', 'method' => 'provides'),
'replace' => 'replaces', 'replace' => array('description' => 'replaces', 'method' => 'replaces'),
'recommend' => 'recommends', 'require-dev' => array('description' => 'requires (for development)', 'method' => 'devRequires'),
'suggest' => 'suggests',
); );
protected $name; protected $name;

View File

@ -12,6 +12,7 @@
namespace Composer\Package\Dumper; namespace Composer\Package\Dumper;
use Composer\Package\BasePackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
/** /**
@ -26,7 +27,6 @@ class ArrayDumper
'binaries' => 'bin', 'binaries' => 'bin',
'scripts', 'scripts',
'type', 'type',
'names',
'extra', 'extra',
'installationSource' => 'installation-source', 'installationSource' => 'installation-source',
'license', 'license',
@ -36,6 +36,7 @@ class ArrayDumper
'keywords', 'keywords',
'autoload', 'autoload',
'repositories', 'repositories',
'includePaths' => 'include-path',
); );
$data = array(); $data = array();
@ -64,14 +65,18 @@ class ArrayDumper
$data['dist']['shasum'] = $package->getDistSha1Checksum(); $data['dist']['shasum'] = $package->getDistSha1Checksum();
} }
foreach (array('require', 'conflict', 'provide', 'replace', 'suggest', 'recommend') as $linkType) { foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if ($links = $package->{'get'.ucfirst($linkType).'s'}()) { if ($links = $package->{'get'.ucfirst($opts['method'])}()) {
foreach ($links as $link) { 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) { foreach ($keys as $method => $key) {
if (is_numeric($method)) { if (is_numeric($method)) {
$method = $key; $method = $key;

View File

@ -156,15 +156,19 @@ class ArrayLoader
} }
} }
foreach (Package\BasePackage::$supportedLinkTypes as $type => $description) { foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
if (isset($config[$type])) { if (isset($config[$type])) {
$method = 'set'.ucfirst($description); $method = 'set'.ucfirst($opts['method']);
$package->{$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'])) { if (isset($config['autoload'])) {
$package->setAutoload($config['autoload']); $package->setAutoload($config['autoload']);
} }

View File

@ -69,13 +69,17 @@ class Locker
* *
* @return array * @return array
*/ */
public function getLockedPackages() public function getLockedPackages($dev = false)
{ {
$lockList = $this->getLockData(); $lockList = $this->getLockData();
$packages = array(); $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']; $resolvedVersion = !empty($info['alias']) ? $info['alias'] : $info['version'];
$package = $this->repositoryManager->getLocalRepository()->findPackage($info['package'], $resolvedVersion); $package = $repo->findPackage($info['package'], $resolvedVersion);
if (!$package) { if (!$package) {
$package = $this->repositoryManager->findPackage($info['package'], $info['version']); $package = $this->repositoryManager->findPackage($info['package'], $info['version']);
@ -120,18 +124,37 @@ class Locker
* Locks provided data into lockfile. * Locks provided data into lockfile.
* *
* @param array $packages array of packages * @param array $packages array of packages
* @param array $packages array of dev packages
* @param array $aliases array of aliases * @param array $aliases array of aliases
* *
* @return Boolean * @return Boolean
*/ */
public function setLockData(array $packages, array $aliases) public function setLockData(array $packages, array $devPackages, array $aliases)
{ {
$lock = array( $lock = array(
'hash' => $this->hash, 'hash' => $this->hash,
'packages' => array(), 'packages' => array(),
'packages-dev' => array(),
'aliases' => $aliases, '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) { foreach ($packages as $package) {
$name = $package->getPrettyName(); $name = $package->getPrettyName();
$version = $package->getPrettyVersion(); $version = $package->getPrettyVersion();
@ -152,20 +175,13 @@ class Locker
$spec['alias'] = $package->getAlias(); $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']); return strcmp($a['package'], $b['package']);
}); });
if (!$this->isLocked() || $lock !== $this->getLockData()) { return $locked;
$this->lockFile->write($lock);
$this->lockDataCache = null;
return true;
}
return false;
} }
} }

View File

@ -53,7 +53,7 @@ class MemoryPackage extends BasePackage
protected $conflicts = array(); protected $conflicts = array();
protected $provides = array(); protected $provides = array();
protected $replaces = array(); protected $replaces = array();
protected $recommends = array(); protected $devRequires = array();
protected $suggests = array(); protected $suggests = array();
protected $autoload = array(); protected $autoload = array();
protected $includePaths = array(); protected $includePaths = array();
@ -484,25 +484,25 @@ class MemoryPackage extends BasePackage
/** /**
* Set the recommended packages * 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} * {@inheritDoc}
*/ */
public function getRecommends() public function getDevRequires()
{ {
return $this->recommends; return $this->devRequires;
} }
/** /**
* Set the suggested packages * 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) public function setSuggests(array $suggests)
{ {

View File

@ -220,20 +220,18 @@ interface PackageInterface
function getReplaces(); function getReplaces();
/** /**
* Returns a set of links to packages which are recommended in * Returns a set of links to packages which are required to develop
* combination with this package. These would most likely be installed * this package. These are installed if in dev mode.
* automatically in combination with this package.
* *
* @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 * Returns a set of package names and reasons why they are useful in
* with this package. These can be suggested to the user, but will not be * combination with this package.
* automatically installed with this package.
* *
* @return array An array of package links defining suggested packages * @return array An array of package suggestions with descriptions
*/ */
function getSuggests(); function getSuggests();

View File

@ -25,6 +25,7 @@ use Composer\Config;
class RepositoryManager class RepositoryManager
{ {
private $localRepository; private $localRepository;
private $localDevRepository;
private $repositories = array(); private $repositories = array();
private $repositoryClasses = array(); private $repositoryClasses = array();
private $io; private $io;
@ -140,4 +141,34 @@ class RepositoryManager
{ {
return $this->localRepository; 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);
}
} }

View File

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

View File

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

View File

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

View File

@ -19,6 +19,11 @@ use Composer\DependencyResolver\Operation\UninstallOperation;
class InstallationManagerTest extends \PHPUnit_Framework_TestCase class InstallationManagerTest extends \PHPUnit_Framework_TestCase
{ {
public function setUp()
{
$this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
}
public function testVendorDirOutsideTheWorkingDir() public function testVendorDirOutsideTheWorkingDir()
{ {
$manager = new InstallationManager(realpath(getcwd().'/../')); $manager = new InstallationManager(realpath(getcwd().'/../'));
@ -70,19 +75,19 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$manager $manager
->expects($this->once()) ->expects($this->once())
->method('install') ->method('install')
->with($installOperation); ->with($this->repository, $installOperation);
$manager $manager
->expects($this->once()) ->expects($this->once())
->method('uninstall') ->method('uninstall')
->with($removeOperation); ->with($this->repository, $removeOperation);
$manager $manager
->expects($this->once()) ->expects($this->once())
->method('update') ->method('update')
->with($updateOperation); ->with($this->repository, $updateOperation);
$manager->execute($installOperation); $manager->execute($this->repository, $installOperation);
$manager->execute($removeOperation); $manager->execute($this->repository, $removeOperation);
$manager->execute($updateOperation); $manager->execute($this->repository, $updateOperation);
} }
public function testInstall() public function testInstall()
@ -108,9 +113,9 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$installer $installer
->expects($this->once()) ->expects($this->once())
->method('install') ->method('install')
->with($package); ->with($this->repository, $package);
$manager->install($operation); $manager->install($this->repository, $operation);
} }
public function testUpdateWithEqualTypes() public function testUpdateWithEqualTypes()
@ -141,9 +146,9 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$installer $installer
->expects($this->once()) ->expects($this->once())
->method('update') ->method('update')
->with($initial, $target); ->with($this->repository, $initial, $target);
$manager->update($operation); $manager->update($this->repository, $operation);
} }
public function testUpdateWithNotEqualTypes() public function testUpdateWithNotEqualTypes()
@ -183,14 +188,14 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$libInstaller $libInstaller
->expects($this->once()) ->expects($this->once())
->method('uninstall') ->method('uninstall')
->with($initial); ->with($this->repository, $initial);
$bundleInstaller $bundleInstaller
->expects($this->once()) ->expects($this->once())
->method('install') ->method('install')
->with($target); ->with($this->repository, $target);
$manager->update($operation); $manager->update($this->repository, $operation);
} }
public function testUninstall() public function testUninstall()
@ -210,7 +215,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$installer $installer
->expects($this->once()) ->expects($this->once())
->method('uninstall') ->method('uninstall')
->with($package); ->with($this->repository, $package);
$installer $installer
->expects($this->once()) ->expects($this->once())
@ -218,7 +223,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
->with('library') ->with('library')
->will($this->returnValue(true)); ->will($this->returnValue(true));
$manager->uninstall($operation); $manager->uninstall($this->repository, $operation);
} }
public function testGetVendorPathAbsolute() public function testGetVendorPathAbsolute()

View File

@ -34,11 +34,9 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->repository = $this->getMockBuilder('Composer\Repository\WritableRepositoryInterface') $this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
->getMock();
$this->io = $this->getMockBuilder('Composer\IO\IOInterface') $this->io = $this->getMock('Composer\IO\IOInterface');
->getMock();
} }
public function testInstallNewInstaller() public function testInstallNewInstaller()
@ -47,7 +45,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->once()) ->expects($this->once())
->method('getPackages') ->method('getPackages')
->will($this->returnValue(array())); ->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; $test = $this;
$this->im $this->im
@ -57,7 +55,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
$test->assertEquals('installer-v1', $installer->version); $test->assertEquals('installer-v1', $installer->version);
})); }));
$installer->install($this->packages[0]); $installer->install($this->repository, $this->packages[0]);
} }
public function testUpgradeWithNewClassName() public function testUpgradeWithNewClassName()
@ -70,7 +68,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->exactly(2)) ->expects($this->exactly(2))
->method('hasPackage') ->method('hasPackage')
->will($this->onConsecutiveCalls(true, false)); ->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; $test = $this;
$this->im $this->im
@ -80,7 +78,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
$test->assertEquals('installer-v2', $installer->version); $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() public function testUpgradeWithSameClassName()
@ -93,7 +91,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->exactly(2)) ->expects($this->exactly(2))
->method('hasPackage') ->method('hasPackage')
->will($this->onConsecutiveCalls(true, false)); ->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; $test = $this;
$this->im $this->im
@ -103,7 +101,7 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
$test->assertEquals('installer-v3', $installer->version); $test->assertEquals('installer-v3', $installer->version);
})); }));
$installer->update($this->packages[1], $this->packages[2]); $installer->update($this->repository, $this->packages[1], $this->packages[2]);
} }
} }

View File

@ -40,11 +40,9 @@ class LibraryInstallerTest extends TestCase
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->repository = $this->getMockBuilder('Composer\Repository\WritableRepositoryInterface') $this->repository = $this->getMock('Composer\Repository\WritableRepositoryInterface');
->getMock();
$this->io = $this->getMockBuilder('Composer\IO\IOInterface') $this->io = $this->getMock('Composer\IO\IOInterface');
->getMock();
} }
protected function tearDown() protected function tearDown()
@ -57,7 +55,7 @@ class LibraryInstallerTest extends TestCase
{ {
$this->fs->removeDirectory($this->vendorDir); $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); $this->assertFileNotExists($this->vendorDir);
} }
@ -65,13 +63,13 @@ class LibraryInstallerTest extends TestCase
{ {
$this->fs->removeDirectory($this->binDir); $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); $this->assertFileNotExists($this->binDir);
} }
public function testIsInstalled() 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(); $package = $this->createPackageMock();
$this->repository $this->repository
@ -80,8 +78,8 @@ class LibraryInstallerTest extends TestCase
->with($package) ->with($package)
->will($this->onConsecutiveCalls(true, false)); ->will($this->onConsecutiveCalls(true, false));
$this->assertTrue($library->isInstalled($package)); $this->assertTrue($library->isInstalled($this->repository, $package));
$this->assertFalse($library->isInstalled($package)); $this->assertFalse($library->isInstalled($this->repository, $package));
} }
/** /**
@ -90,7 +88,7 @@ class LibraryInstallerTest extends TestCase
*/ */
public function testInstall() 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 = $this->createPackageMock();
$package $package
@ -108,7 +106,7 @@ class LibraryInstallerTest extends TestCase
->method('addPackage') ->method('addPackage')
->with($package); ->with($package);
$library->install($package); $library->install($this->repository, $package);
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created'); $this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
$this->assertFileExists($this->binDir, 'Bin dir should be created'); $this->assertFileExists($this->binDir, 'Bin dir should be created');
} }
@ -119,7 +117,7 @@ class LibraryInstallerTest extends TestCase
*/ */
public function testUpdate() 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(); $initial = $this->createPackageMock();
$target = $this->createPackageMock(); $target = $this->createPackageMock();
@ -148,18 +146,18 @@ class LibraryInstallerTest extends TestCase
->method('addPackage') ->method('addPackage')
->with($target); ->with($target);
$library->update($initial, $target); $library->update($this->repository, $initial, $target);
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created'); $this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
$this->assertFileExists($this->binDir, 'Bin dir should be created'); $this->assertFileExists($this->binDir, 'Bin dir should be created');
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
$library->update($initial, $target); $library->update($this->repository, $initial, $target);
} }
public function testUninstall() 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 = $this->createPackageMock();
$package $package
@ -183,17 +181,17 @@ class LibraryInstallerTest extends TestCase
->method('removePackage') ->method('removePackage')
->with($package); ->with($package);
$library->uninstall($package); $library->uninstall($this->repository, $package);
// TODO re-enable once #125 is fixed and we throw exceptions again // TODO re-enable once #125 is fixed and we throw exceptions again
// $this->setExpectedException('InvalidArgumentException'); // $this->setExpectedException('InvalidArgumentException');
$library->uninstall($package); $library->uninstall($this->repository, $package);
} }
public function testGetInstallPath() 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 = $this->createPackageMock();
$package $package
@ -206,7 +204,7 @@ class LibraryInstallerTest extends TestCase
public function testGetInstallPathWithTargetDir() 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 = $this->createPackageMock();
$package $package

View File

@ -26,7 +26,7 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase
$this->io = $this->getMock('Composer\IO\IOInterface'); $this->io = $this->getMock('Composer\IO\IOInterface');
$this->installer = new MetapackageInstaller($this->repository, $this->io); $this->installer = new MetapackageInstaller();
} }
public function testInstall() public function testInstall()
@ -38,7 +38,7 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase
->method('addPackage') ->method('addPackage')
->with($package); ->with($package);
$this->installer->install($package); $this->installer->install($this->repository, $package);
} }
public function testUpdate() public function testUpdate()
@ -62,11 +62,11 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase
->method('addPackage') ->method('addPackage')
->with($target); ->with($target);
$this->installer->update($initial, $target); $this->installer->update($this->repository, $initial, $target);
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
$this->installer->update($initial, $target); $this->installer->update($this->repository, $initial, $target);
} }
public function testUninstall() public function testUninstall()
@ -84,12 +84,12 @@ class MetapackageInstallerTest extends \PHPUnit_Framework_TestCase
->method('removePackage') ->method('removePackage')
->with($package); ->with($package);
$this->installer->uninstall($package); $this->installer->uninstall($this->repository, $package);
// TODO re-enable once #125 is fixed and we throw exceptions again // TODO re-enable once #125 is fixed and we throw exceptions again
// $this->setExpectedException('InvalidArgumentException'); // $this->setExpectedException('InvalidArgumentException');
$this->installer->uninstall($package); $this->installer->uninstall($this->repository, $package);
} }
private function createPackageMock() private function createPackageMock()

View File

@ -14,6 +14,8 @@ namespace Composer\Test\Package\Dumper;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\MemoryPackage; use Composer\Package\MemoryPackage;
use Composer\Package\Link;
use Composer\Package\LinkConstraint\VersionConstraint;
class ArrayDumperTest extends \PHPUnit_Framework_TestCase 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'); $package = new MemoryPackage('foo', '1.0.0.0', '1.0');
$config = $this->dumper->dump($package); $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 * @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'); $package = new MemoryPackage('foo', '1.0.0.0', '1.0');
@ -50,17 +52,70 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
public function getKeys() public function getKeys()
{ {
return array( return array(
array('time', new \DateTime('2012-02-01'), '2012-02-01 00:00:00', 'ReleaseDate'), array(
array('authors', array('Nils Adermann <naderman@naderman.de>', 'Jordi Boggiano <j.boggiano@seld.be>')), 'time',
array('homepage', 'http://getcomposer.org'), new \DateTime('2012-02-01'),
array('description', 'Package Manager'), 'ReleaseDate',
array('keywords', array('package', 'dependency', 'autoload')), '2012-02-01 00:00:00',
array('bin', array('bin/composer'), null, 'binaries'), ),
array('license', array('MIT')), array(
array('autoload', array('psr-0' => array('Composer' => 'src/'))), 'authors',
array('repositories', array('packagist' => false)), array('Nils Adermann <naderman@naderman.de>', 'Jordi Boggiano <j.boggiano@seld.be>')
array('scripts', array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate')), ),
array('extra', array('class' => 'MyVendor\\Installer')), 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'
),
); );
} }
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Test\Package\Loader; namespace Composer\Test\Package\Loader;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Dumper\ArrayDumper;
class ArrayLoaderTest extends \PHPUnit_Framework_TestCase class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
{ {
@ -35,4 +36,88 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
$replaces = $package->getReplaces(); $replaces = $package->getReplaces();
$this->assertEquals('== 1.2.3.4', (string) $replaces[0]->getConstraint()); $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));
}
} }

View File

@ -151,10 +151,11 @@ class LockerTest extends \PHPUnit_Framework_TestCase
array('package' => 'pkg1', 'version' => '1.0.0-beta'), array('package' => 'pkg1', 'version' => '1.0.0-beta'),
array('package' => 'pkg2', 'version' => '0.1.10') array('package' => 'pkg2', 'version' => '0.1.10')
), ),
'packages-dev' => array(),
'aliases' => array(), 'aliases' => array(),
)); ));
$locker->setLockData(array($package1, $package2), array()); $locker->setLockData(array($package1, $package2), array(), array());
} }
public function testLockBadPackages() public function testLockBadPackages()
@ -172,7 +173,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$this->setExpectedException('LogicException'); $this->setExpectedException('LogicException');
$locker->setLockData(array($package1), array()); $locker->setLockData(array($package1), array(), array());
} }
public function testIsFresh() public function testIsFresh()

View File

@ -95,7 +95,7 @@ class FilesystemRepositoryTest extends TestCase
->expects($this->once()) ->expects($this->once())
->method('write') ->method('write')
->with(array( ->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')); $repository->addPackage($this->getPackage('mypkg', '0.1.10'));