Merge pull request #575 from Seldaek/newlinks

New link handling, removed recommend, added require-dev, and changed suggest
main
Nils Adermann 12 years ago
commit 65999c48e1

@ -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

@ -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/" }

@ -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

@ -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 <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.
* **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.

@ -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": {

@ -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(<<<EOT
Displays detailed information about where a package is referenced.
@ -81,10 +84,10 @@ EOT
foreach ($repository->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);

@ -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(<<<EOT
The <info>install</info> 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;

@ -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(<<<EOT
The <info>update</info> 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;
}
}

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

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

@ -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;
/**
@ -123,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;
@ -158,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('<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
$installFromLock = false;
$request = new Request($pool);
if ($this->update) {
$this->io->write('Updating dependencies');
$this->io->write('<info>Updating '.($devMode ? 'dev ': '').'dependencies</info>');
$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('<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>');
}
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()) {
@ -197,15 +217,25 @@ class Installer
$request->install($package->getName(), $constraint);
}
} 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) {
$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);
@ -262,22 +292,35 @@ 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('<info>Nothing to install or update</info>');
$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);
@ -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);
@ -307,40 +350,34 @@ class Installer
}
}
if (!$this->dryRun) {
if ($this->update || !$this->locker->isLocked()) {
if ($this->locker->setLockData($localRepo->getPackages(), $aliases)) {
$this->io->write('<info>Writing lock file</info>');
}
}
$localRepo->write();
$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;
return $suggestedPackages;
}
private function collectLinks()
private function aliasPackages()
{
$links = $this->package->getRequires();
if ($this->installRecommends) {
$links = array_merge($links, $this->package->getRecommends());
if (!$this->update && $this->locker->isLocked()) {
$aliases = $this->locker->getAliases();
} else {
$aliases = $this->package->getAliases();
}
if ($this->installSuggests) {
$links = array_merge($links, $this->package->getSuggests());
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);
}
}
}
return $links;
return $aliases;
}
/**
@ -379,7 +416,7 @@ class Installer
* @param boolean $dryRun
* @return Installer
*/
public function setDryRun($dryRun=true)
public function setDryRun($dryRun = true)
{
$this->dryRun = (boolean) $dryRun;
@ -387,53 +424,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 +468,7 @@ class Installer
* @param boolean $verbose
* @return Installer
*/
public function setVerbose($verbose=true)
public function setVerbose($verbose = true)
{
$this->verbose = (boolean) $verbose;

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

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

@ -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 <ever.zet@gmail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
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

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

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

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

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

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

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

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

@ -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)
{

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

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

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

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

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

@ -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().'/../'));
@ -70,19 +75,19 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$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 +113,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 +146,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 +188,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 +215,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 +223,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
->with('library')
->will($this->returnValue(true));
$manager->uninstall($operation);
$manager->uninstall($this->repository, $operation);
}
public function testGetVendorPathAbsolute()

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

@ -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

@ -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()

@ -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 <naderman@naderman.de>', 'Jordi Boggiano <j.boggiano@seld.be>')),
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 <naderman@naderman.de>', 'Jordi Boggiano <j.boggiano@seld.be>')
),
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'
),
);
}
}

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

@ -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()

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

Loading…
Cancel
Save