LibraryInstaller refactored and tested
parent
0cc017a395
commit
067007656b
|
@ -12,14 +12,53 @@
|
||||||
|
|
||||||
namespace Composer\Installer;
|
namespace Composer\Installer;
|
||||||
|
|
||||||
|
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Downloader\DownloaderInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Interface for the package installation manager.
|
||||||
|
*
|
||||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||||
*/
|
*/
|
||||||
interface InstallerInterface
|
interface InstallerInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Executes specific solver operation.
|
||||||
|
*
|
||||||
|
* @param OperationInterface $operation solver operation instance
|
||||||
|
*/
|
||||||
|
function executeOperation(OperationInterface $operation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that provided package is installed.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
function isInstalled(PackageInterface $package);
|
function isInstalled(PackageInterface $package);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs specific package.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
*/
|
||||||
function install(PackageInterface $package);
|
function install(PackageInterface $package);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates specific package.
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstalls specific package.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
*/
|
||||||
|
function uninstall(PackageInterface $package);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,24 +12,35 @@
|
||||||
|
|
||||||
namespace Composer\Installer;
|
namespace Composer\Installer;
|
||||||
|
|
||||||
use Composer\Downloader\DownloaderInterface;
|
use Composer\Downloader\DownloadManager;
|
||||||
|
use Composer\Installer\Registry\RegistryInterface;
|
||||||
|
use Composer\Installer\Registry\FilesystemRegistry;
|
||||||
|
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Downloader\DownloaderInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Package installation manager.
|
||||||
|
*
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||||
*/
|
*/
|
||||||
class LibraryInstaller implements InstallerInterface
|
class LibraryInstaller implements InstallerInterface
|
||||||
{
|
{
|
||||||
private $dir;
|
private $dir;
|
||||||
private $preferSource;
|
private $dm;
|
||||||
private $downloaders = array();
|
private $registry;
|
||||||
|
|
||||||
public function __construct($dir = 'vendor', $preferSource = false)
|
/**
|
||||||
|
* Initializes library installer.
|
||||||
|
*
|
||||||
|
* @param string $dir relative path for packages home
|
||||||
|
* @param DownloadManager $dm download manager
|
||||||
|
* @param RegistryInterface $registry registry controller
|
||||||
|
*/
|
||||||
|
public function __construct($dir, DownloadManager $dm, RegistryInterface $registry = null)
|
||||||
{
|
{
|
||||||
$this->dir = $dir;
|
$this->dir = $dir;
|
||||||
$this->preferSource = $preferSource;
|
$this->dm = $dm;
|
||||||
|
|
||||||
if (!is_dir($this->dir)) {
|
if (!is_dir($this->dir)) {
|
||||||
if (file_exists($this->dir)) {
|
if (file_exists($this->dir)) {
|
||||||
|
@ -43,67 +54,99 @@ class LibraryInstaller implements InstallerInterface
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null === $registry) {
|
||||||
|
$registry = new FilesystemRegistry('.composer', str_replace('/', '_', $dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDownloader($type, DownloaderInterface $downloader = null)
|
$this->registry = $registry;
|
||||||
|
$this->registry->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes packages registry.
|
||||||
|
*/
|
||||||
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (null === $downloader) {
|
$this->registry->close();
|
||||||
unset($this->downloaders[$type]);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->downloaders[$type] = $downloader;
|
/**
|
||||||
}
|
* Executes specific solver operation.
|
||||||
|
*
|
||||||
public function getDownloader($type)
|
* @param OperationInterface $operation solver operation instance
|
||||||
|
*/
|
||||||
|
public function executeOperation(OperationInterface $operation)
|
||||||
{
|
{
|
||||||
if (!isset($this->downloaders[$type])) {
|
$method = $operation->getJobType();
|
||||||
throw new \UnexpectedValueException('Unknown source type: '.$type);
|
|
||||||
}
|
if ('update' === $method) {
|
||||||
|
$this->$method($operation->getPackage(), $operation->getTargetPackage());
|
||||||
return $this->downloaders[$type];
|
} else {
|
||||||
}
|
$this->$method($operation->getPackage());
|
||||||
|
}
|
||||||
public function install(PackageInterface $package)
|
|
||||||
{
|
|
||||||
if (!($this->preferSource && $package->getSourceType()) && $package->getDistType()) {
|
|
||||||
$downloader = $this->getDownloader($package->getDistType());
|
|
||||||
|
|
||||||
return $downloader->download(
|
|
||||||
$package, $this->dir, $package->getDistUrl(), $package->getDistSha1Checksum()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($package->getSourceType()) {
|
|
||||||
$downloader = $this->getDownloader($package->getSourceType());
|
|
||||||
|
|
||||||
return $downloader->download(
|
|
||||||
$package, $this->dir, $package->getSourceUrl()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \InvalidArgumentException('Package should have dist or source specified');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that specific package is installed.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
public function isInstalled(PackageInterface $package)
|
public function isInstalled(PackageInterface $package)
|
||||||
{
|
{
|
||||||
if ($package->getSourceType()) {
|
return $this->registry->isPackageRegistered($package);
|
||||||
$downloader = $this->getDownloader($package->getSourceType());
|
|
||||||
|
|
||||||
if ($downloader->isDownloaded($package, $this->dir)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($package->getDistType()) {
|
/**
|
||||||
$downloader = $this->getDownloader($package->getDistType());
|
* Installs specific package.
|
||||||
|
*
|
||||||
if ($downloader->isDownloaded($package, $this->dir)) {
|
* @param PackageInterface $package package instance
|
||||||
return true;
|
*
|
||||||
}
|
* @throws InvalidArgumentException if provided package have no urls to download from
|
||||||
|
*/
|
||||||
|
public function install(PackageInterface $package)
|
||||||
|
{
|
||||||
|
$type = $this->dm->download($package, $this->dir);
|
||||||
|
$this->registry->registerPackage($package, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Updates specific package.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $initial already installed package version
|
||||||
|
* @param PackageInterface $target updated version
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if $from package is not installed
|
||||||
|
*/
|
||||||
|
public function update(PackageInterface $initial, PackageInterface $target)
|
||||||
|
{
|
||||||
|
if (!$this->registry->isPackageRegistered($initial)) {
|
||||||
|
throw new \UnexpectedValueException('Package is not installed: '.$initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $this->registry->getRegisteredPackageInstallerType($initial);
|
||||||
|
$this->dm->update($initial, $target, $this->dir, $type);
|
||||||
|
$this->registry->unregisterPackage($initial);
|
||||||
|
$this->registry->registerPackage($target, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstalls specific package.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if package is not installed
|
||||||
|
*/
|
||||||
|
public function uninstall(PackageInterface $package)
|
||||||
|
{
|
||||||
|
if (!$this->registry->isPackageRegistered($package)) {
|
||||||
|
throw new \UnexpectedValueException('Package is not installed: '.$package);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $this->registry->getRegisteredPackageInstallerType($package);
|
||||||
|
$this->dm->remove($package, $this->dir, $type);
|
||||||
|
$this->registry->unregisterPackage($package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
<?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\Test\Installer;
|
||||||
|
|
||||||
|
use Composer\Installer\LibraryInstaller;
|
||||||
|
use Composer\DependencyResolver\Operation;
|
||||||
|
|
||||||
|
class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $dir;
|
||||||
|
private $dm;
|
||||||
|
private $registry;
|
||||||
|
private $library;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->dir = sys_get_temp_dir().'/composer';
|
||||||
|
if (is_dir($this->dir)) {
|
||||||
|
rmdir($this->dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dm = $this->getMockBuilder('Composer\Downloader\DownloadManager')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->registry = $this->getMockBuilder('Composer\Installer\Registry\RegistryInterface')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallerCreation()
|
||||||
|
{
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('open');
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('close');
|
||||||
|
|
||||||
|
$library = new LibraryInstaller($this->dir, $this->dm, $this->registry);
|
||||||
|
$this->assertTrue(is_dir($this->dir));
|
||||||
|
|
||||||
|
$file = sys_get_temp_dir().'/file';
|
||||||
|
touch($file);
|
||||||
|
|
||||||
|
$this->setExpectedException('UnexpectedValueException');
|
||||||
|
$library = new LibraryInstaller($file, $this->dm, $this->registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteOperation()
|
||||||
|
{
|
||||||
|
$library = $this->getMockBuilder('Composer\Installer\LibraryInstaller')
|
||||||
|
->setConstructorArgs(array($this->dir, $this->dm, $this->registry))
|
||||||
|
->setMethods(array('install', 'update', 'uninstall'))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$packageToInstall = $this->createPackageMock();
|
||||||
|
$packageToRemove = $this->createPackageMock();
|
||||||
|
$packageToUpdate = $this->createPackageMock();
|
||||||
|
$updatedPackage = $this->createPackageMock();
|
||||||
|
|
||||||
|
$library
|
||||||
|
->expects($this->once())
|
||||||
|
->method('install')
|
||||||
|
->with($packageToInstall);
|
||||||
|
|
||||||
|
$library
|
||||||
|
->expects($this->once())
|
||||||
|
->method('uninstall')
|
||||||
|
->with($packageToRemove);
|
||||||
|
|
||||||
|
$library
|
||||||
|
->expects($this->once())
|
||||||
|
->method('update')
|
||||||
|
->with($packageToUpdate, $updatedPackage);
|
||||||
|
|
||||||
|
$library->executeOperation(new Operation\InstallOperation($packageToInstall));
|
||||||
|
$library->executeOperation(new Operation\UninstallOperation($packageToRemove));
|
||||||
|
$library->executeOperation(new Operation\UpdateOperation($packageToUpdate, $updatedPackage));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsInstalled()
|
||||||
|
{
|
||||||
|
$library = new LibraryInstaller($this->dir, $this->dm, $this->registry);
|
||||||
|
$package = $this->createPackageMock();
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->exactly(2))
|
||||||
|
->method('isPackageRegistered')
|
||||||
|
->with($package)
|
||||||
|
->will($this->onConsecutiveCalls(true, false));
|
||||||
|
|
||||||
|
$this->assertTrue($library->isInstalled($package));
|
||||||
|
$this->assertFalse($library->isInstalled($package));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstall()
|
||||||
|
{
|
||||||
|
$library = new LibraryInstaller($this->dir, $this->dm, $this->registry);
|
||||||
|
$package = $this->createPackageMock();
|
||||||
|
|
||||||
|
$this->dm
|
||||||
|
->expects($this->once())
|
||||||
|
->method('download')
|
||||||
|
->with($package, $this->dir)
|
||||||
|
->will($this->returnValue('source'));
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('registerPackage')
|
||||||
|
->with($package, 'source');
|
||||||
|
|
||||||
|
$library->install($package);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate()
|
||||||
|
{
|
||||||
|
$library = new LibraryInstaller($this->dir, $this->dm, $this->registry);
|
||||||
|
$initial = $this->createPackageMock();
|
||||||
|
$target = $this->createPackageMock();
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->exactly(2))
|
||||||
|
->method('isPackageRegistered')
|
||||||
|
->with($initial)
|
||||||
|
->will($this->onConsecutiveCalls(true, false));
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getRegisteredPackageInstallerType')
|
||||||
|
->with($initial)
|
||||||
|
->will($this->returnValue('dist'));
|
||||||
|
|
||||||
|
$this->dm
|
||||||
|
->expects($this->once())
|
||||||
|
->method('update')
|
||||||
|
->with($initial, $target, $this->dir, 'dist');
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('unregisterPackage')
|
||||||
|
->with($initial);
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('registerPackage')
|
||||||
|
->with($target, 'dist');
|
||||||
|
|
||||||
|
$library->update($initial, $target);
|
||||||
|
|
||||||
|
$this->setExpectedException('UnexpectedValueException');
|
||||||
|
|
||||||
|
$library->update($initial, $target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUninstall()
|
||||||
|
{
|
||||||
|
$library = new LibraryInstaller($this->dir, $this->dm, $this->registry);
|
||||||
|
$package = $this->createPackageMock();
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->exactly(2))
|
||||||
|
->method('isPackageRegistered')
|
||||||
|
->with($package)
|
||||||
|
->will($this->onConsecutiveCalls(true, false));
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getRegisteredPackageInstallerType')
|
||||||
|
->with($package)
|
||||||
|
->will($this->returnValue('source'));
|
||||||
|
|
||||||
|
$this->dm
|
||||||
|
->expects($this->once())
|
||||||
|
->method('remove')
|
||||||
|
->with($package, $this->dir, 'source');
|
||||||
|
|
||||||
|
$this->registry
|
||||||
|
->expects($this->once())
|
||||||
|
->method('unregisterPackage')
|
||||||
|
->with($package);
|
||||||
|
|
||||||
|
$library->uninstall($package);
|
||||||
|
|
||||||
|
$this->setExpectedException('UnexpectedValueException');
|
||||||
|
|
||||||
|
$library->uninstall($package);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createPackageMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Composer\Package\MemoryPackage')
|
||||||
|
->setConstructorArgs(array(md5(rand()), '1.0.0'))
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue