Allow notification from locked installs, fixes #1368, fixes #1372, fixes #1369

main
Jordi Boggiano 12 years ago
parent e868c9706b
commit a8f74a0983

@ -16,14 +16,15 @@ use Composer\Config;
use Composer\Factory;
use Composer\Installer;
use Composer\Installer\ProjectInstaller;
use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface;
use Composer\Package\BasePackage;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\Repository\ComposerRepository;
use Composer\Repository\CompositeRepository;
use Composer\Repository\FilesystemRepository;
use Composer\Repository\NotifiableRepositoryInterface;
use Composer\Repository\InstalledFilesystemRepository;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@ -117,11 +118,6 @@ EOT
throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::$stabilities)));
}
$dm = $this->createDownloadManager($io, $config);
if ($preferSource) {
$dm->setPreferSource(true);
}
if (null === $repositoryUrl) {
$sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config));
} elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION)) {
@ -179,13 +175,16 @@ EOT
$package->setSourceReference(substr($package->getPrettyVersion(), 4));
}
$dm = $this->createDownloadManager($io, $config);
$dm->setPreferSource($preferSource)
->setPreferDist($preferDist);
$projectInstaller = new ProjectInstaller($directory, $dm);
$projectInstaller->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), $package);
if ($package->getRepository() instanceof NotifiableRepositoryInterface) {
$package->getRepository()->notifyInstall($package);
}
$im = $this->createInstallationManager();
$im->addInstaller($projectInstaller);
$im->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package));
$im->notifyInstalls();
$installedFromVcs = 'source' === $package->getInstallationSource();
$io->write('<info>Created project in ' . $directory . '</info>');
@ -194,7 +193,7 @@ EOT
putenv('COMPOSER_ROOT_VERSION='.$package->getPrettyVersion());
// clean up memory
unset($dm, $config, $projectInstaller, $sourceRepo, $package);
unset($dm, $im, $config, $projectInstaller, $sourceRepo, $package);
// install dependencies of the created project
$composer = Factory::create($io);
@ -248,4 +247,9 @@ EOT
return $factory->createDownloadManager($io, $config);
}
protected function createInstallationManager()
{
return new InstallationManager();
}
}

@ -223,7 +223,7 @@ class Factory
$dm = $this->createDownloadManager($io, $config);
// initialize installation manager
$im = $this->createInstallationManager($config);
$im = $this->createInstallationManager();
// initialize composer
$composer = new Composer();
@ -305,12 +305,11 @@ class Factory
}
/**
* @param Config $config
* @return Installer\InstallationManager
*/
protected function createInstallationManager(Config $config)
protected function createInstallationManager()
{
return new Installer\InstallationManager($config->get('vendor-dir'));
return new Installer\InstallationManager();
}
/**

@ -15,7 +15,6 @@ namespace Composer\Installer;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\NotifiableRepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\InstallOperation;
@ -23,6 +22,7 @@ use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
use Composer\Util\StreamContextFactory;
/**
* Package operation manager.
@ -52,6 +52,19 @@ class InstallationManager
$this->cache = array();
}
/**
* Removes installer
*
* @param InstallerInterface $installer installer instance
*/
public function removeInstaller(InstallerInterface $installer)
{
if (false !== ($key = array_search($installer, $this->installers, true))) {
array_splice($this->installers, $key, 1);
$this->cache = array();
}
}
/**
* Disables custom installers.
*
@ -219,16 +232,60 @@ class InstallationManager
public function notifyInstalls()
{
foreach ($this->notifiablePackages as $packages) {
$repo = reset($packages)->getRepository();
$repo->notifyInstalls($packages);
foreach ($this->notifiablePackages as $repoUrl => $packages) {
// non-batch API, deprecated
if (strpos($repoUrl, '%package%')) {
foreach ($packages as $package) {
$url = str_replace('%package%', $package->getPrettyName(), $repoUrl);
$params = array(
'version' => $package->getPrettyVersion(),
'version_normalized' => $package->getVersion(),
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($params, '', '&'),
'timeout' => 3,
)
);
$context = StreamContextFactory::getContext($opts);
@file_get_contents($url, false, $context);
}
return;
}
$postData = array('downloads' => array());
foreach ($packages as $package) {
$postData['downloads'][] = array(
'name' => $package->getPrettyName(),
'version' => $package->getVersion(),
);
}
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode($postData),
'timeout' => 6,
)
);
$context = StreamContextFactory::getContext($opts);
@file_get_contents($repoUrl, false, $context);
}
$this->reset();
}
private function markForNotification(PackageInterface $package)
{
if ($package->getRepository() instanceof NotifiableRepositoryInterface) {
$this->notifiablePackages[spl_object_hash($package->getRepository())][$package->getName()] = $package;
if ($package->getNotificationUrl()) {
$this->notifiablePackages[$package->getNotificationUrl()][$package->getName()] = $package;
}
}
}

@ -307,6 +307,10 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
{
return $this->aliasOf->getSupport();
}
public function getNotificationUrl()
{
return $this->aliasOf->getNotificationUrl();
}
public function __toString()
{
return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';

@ -31,6 +31,7 @@ class ArrayDumper
'extra',
'installationSource' => 'installation-source',
'autoload',
'notificationUrl' => 'notification-url',
'includePaths' => 'include-path',
);

@ -142,6 +142,10 @@ class ArrayLoader implements LoaderInterface
}
}
if (!empty($config['notification-url'])) {
$package->setNotificationUrl($config['notification-url']);
}
if ($package instanceof Package\CompletePackageInterface) {
if (isset($config['scripts']) && is_array($config['scripts'])) {
foreach ($config['scripts'] as $event => $listeners) {

@ -41,6 +41,7 @@ class Package extends BasePackage
protected $prettyAlias;
protected $dev;
protected $stability;
protected $notificationUrl;
protected $requires = array();
protected $conflicts = array();
@ -506,4 +507,22 @@ class Package extends BasePackage
{
return $this->includePaths;
}
/**
* Sets the notification URL
*
* @param string $notificationUrl
*/
public function setNotificationUrl($notificationUrl)
{
$this->notificationUrl = $notificationUrl;
}
/**
* {@inheritDoc}
*/
public function getNotificationUrl()
{
return $this->notificationUrl;
}
}

@ -288,6 +288,13 @@ interface PackageInterface
*/
public function getUniqueName();
/**
* Returns the package notification url
*
* @return string
*/
public function getNotificationUrl();
/**
* Converts the package into a readable and unique string
*

@ -22,12 +22,11 @@ use Composer\Cache;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\RemoteFilesystem;
use Composer\Util\StreamContextFactory;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ComposerRepository extends ArrayRepository implements NotifiableRepositoryInterface, StreamableRepositoryInterface
class ComposerRepository extends ArrayRepository implements StreamableRepositoryInterface
{
protected $config;
protected $options;
@ -77,61 +76,6 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
$this->loader = new ArrayLoader();
}
/**
* {@inheritDoc}
*/
public function notifyInstalls(array $packages)
{
if (!$this->notifyUrl || !$this->config->get('notify-on-install')) {
return;
}
// non-batch API, deprecated
if (strpos($this->notifyUrl, '%package%')) {
foreach ($packages as $package) {
$url = str_replace('%package%', $package->getPrettyName(), $this->notifyUrl);
$params = array(
'version' => $package->getPrettyVersion(),
'version_normalized' => $package->getVersion(),
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($params, '', '&'),
'timeout' => 3,
)
);
$context = StreamContextFactory::getContext($opts);
@file_get_contents($url, false, $context);
}
return;
}
$postData = array('downloads' => array());
foreach ($packages as $package) {
$postData['downloads'][] = array(
'name' => $package->getPrettyName(),
'version' => $package->getVersion(),
);
}
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode($postData),
'timeout' => 6,
)
);
$context = StreamContextFactory::getContext($opts);
@file_get_contents($this->notifyUrl, false, $context);
}
public function setRootAliases(array $rootAliases)
{
$this->rootAliases = $rootAliases;
@ -459,6 +403,8 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
protected function createPackage(array $data, $class)
{
try {
$data['notification-url'] = $this->notifyUrl;
return $this->loader->load($data, 'Composer\Package\CompletePackage');
} catch (\Exception $e) {
throw new \RuntimeException('Could not load package '.(isset($data['name']) ? $data['name'] : json_encode($data)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e);

@ -1,28 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Repository;
use Composer\Package\PackageInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
interface NotifiableRepositoryInterface extends RepositoryInterface
{
/**
* Notify this repository about the installation of a package
*
* @param PackageInterface[] $packages Packages that were installed
*/
public function notifyInstalls(array $packages);
}

@ -35,7 +35,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
return $arg === 'vendor';
}));
$manager = new InstallationManager('vendor');
$manager = new InstallationManager();
$manager->addInstaller($installer);
$this->assertSame($installer, $manager->getInstaller('vendor'));
@ -44,6 +44,36 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
$manager->getInstaller('unregistered');
}
public function testAddRemoveInstaller()
{
$installer = $this->createInstallerMock();
$installer
->expects($this->exactly(2))
->method('supports')
->will($this->returnCallback(function ($arg) {
return $arg === 'vendor';
}));
$installer2 = $this->createInstallerMock();
$installer2
->expects($this->exactly(1))
->method('supports')
->will($this->returnCallback(function ($arg) {
return $arg === 'vendor';
}));
$manager = new InstallationManager();
$manager->addInstaller($installer);
$this->assertSame($installer, $manager->getInstaller('vendor'));
$manager->addInstaller($installer2);
$this->assertSame($installer2, $manager->getInstaller('vendor'));
$manager->removeInstaller($installer2);
$this->assertSame($installer, $manager->getInstaller('vendor'));
}
public function testExecute()
{
$manager = $this->getMockBuilder('Composer\Installer\InstallationManager')
@ -77,7 +107,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
public function testInstall()
{
$installer = $this->createInstallerMock();
$manager = new InstallationManager('vendor');
$manager = new InstallationManager();
$manager->addInstaller($installer);
$package = $this->createPackageMock();
@ -105,7 +135,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
public function testUpdateWithEqualTypes()
{
$installer = $this->createInstallerMock();
$manager = new InstallationManager('vendor');
$manager = new InstallationManager();
$manager->addInstaller($installer);
$initial = $this->createPackageMock();
@ -139,7 +169,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
{
$libInstaller = $this->createInstallerMock();
$bundleInstaller = $this->createInstallerMock();
$manager = new InstallationManager('vendor');
$manager = new InstallationManager();
$manager->addInstaller($libInstaller);
$manager->addInstaller($bundleInstaller);
@ -185,7 +215,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase
public function testUninstall()
{
$installer = $this->createInstallerMock();
$manager = new InstallationManager('vendor');
$manager = new InstallationManager();
$manager->addInstaller($installer);
$package = $this->createPackageMock();

Loading…
Cancel
Save