From 30e89a2402489a9ca40fc2ce039af45601a16744 Mon Sep 17 00:00:00 2001 From: digitalkaoz Date: Mon, 23 Jan 2012 15:19:05 +0100 Subject: [PATCH] fixed broken packages on filesystem --- src/Composer/Command/InstallCommand.php | 6 +- .../Operation/ReplaceOperation.php | 66 +++++++++++++++++++ .../Installer/InstallationManager.php | 12 ++++ src/Composer/Installer/InstallerInterface.php | 7 ++ src/Composer/Installer/LibraryInstaller.php | 19 +++++- src/Composer/Package/BasePackage.php | 11 ++++ .../installer-v1/Installer/Custom.php | 1 + .../installer-v2/Installer/Custom2.php | 1 + .../installer-v3/Installer/Custom2.php | 1 + .../Test/Installer/LibraryInstallerTest.php | 24 +++++++ 10 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/Composer/DependencyResolver/Operation/ReplaceOperation.php diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index bf8bca726..dbacf89d5 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -23,6 +23,7 @@ use Composer\Repository\PlatformRepository; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Composer\DependencyResolver\Operation\ReplaceOperation; /** * @author Jordi Boggiano @@ -132,7 +133,10 @@ EOT // TODO this belongs in the solver, but this will do for now to report top-level deps missing at least foreach ($request->getJobs() as $job) { if ('install' === $job['cmd']) { - foreach ($installedRepo->getPackages() as $package) { + foreach ($installedRepo->getPackages() as $package ) { + if ($installedRepo->hasPackage($package) && !$package->isPlatform() && !$installationManager->isPackageInstalled($package)) { + $operations[$job['packageName']] = new ReplaceOperation($package, \Composer\DependencyResolver\Solver::RULE_PACKAGE_NOT_EXIST); + } if (in_array($job['packageName'], $package->getNames())) { continue 2; } diff --git a/src/Composer/DependencyResolver/Operation/ReplaceOperation.php b/src/Composer/DependencyResolver/Operation/ReplaceOperation.php new file mode 100644 index 000000000..1944355ac --- /dev/null +++ b/src/Composer/DependencyResolver/Operation/ReplaceOperation.php @@ -0,0 +1,66 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\DependencyResolver\Operation; + +use Composer\Package\PackageInterface; + +/** + * Solver replace operation. + * + * @author Robert Schönthal + */ +class ReplaceOperation extends SolverOperation +{ + protected $package; + + /** + * Initializes operation. + * + * @param PackageInterface $package package instance + * @param string $reason operation reason + */ + public function __construct(PackageInterface $package, $reason = null) + { + parent::__construct($reason); + + $this->package = $package; + } + + /** + * Returns package instance. + * + * @return PackageInterface + */ + public function getPackage() + { + return $this->package; + } + + /** + * Returns job type. + * + * @return string + */ + public function getJobType() + { + return 'replace'; + } + + /** + * {@inheritDoc} + */ + public function __toString() + { + return 'Replacing '.$this->package->getPrettyName().' ('.$this->package->getPrettyVersion().')'; + } +} diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 2acb09d5b..2e7404299 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -17,6 +17,7 @@ use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\InstallOperation; use Composer\DependencyResolver\Operation\UpdateOperation; use Composer\DependencyResolver\Operation\UninstallOperation; +use Composer\DependencyResolver\Operation\ReplaceOperation; /** * Package operation manager. @@ -160,6 +161,17 @@ class InstallationManager $installer->uninstall($operation->getPackage()); } + /** + * Replaces package. + * + * @param ReplaceOperation $operation operation instance + */ + public function replace(ReplaceOperation $operation) + { + $installer = $this->getInstaller($operation->getPackage()->getType()); + $installer->replace($operation->getPackage()); + } + /** * Returns the installation path of a package * diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index 36c023b3b..9e8eafdf1 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -63,6 +63,13 @@ interface InstallerInterface */ function uninstall(PackageInterface $package); + /** + * Replaces specific package. + * + * @param PackageInterface $package package instance + */ + function replace(PackageInterface $package); + /** * Returns the installation path of a package * diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 319ac9e98..33624cb47 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -72,7 +72,7 @@ class LibraryInstaller implements InstallerInterface */ public function isInstalled(PackageInterface $package) { - return $this->repository->hasPackage($package); + return $this->repository->hasPackage($package) && is_readable($this->getInstallPath($package)); } /** @@ -123,6 +123,23 @@ class LibraryInstaller implements InstallerInterface $this->repository->removePackage($package); } + /** + * {@inheritDoc} + */ + public function replace(PackageInterface $package) + { + if (!$this->repository->hasPackage($package)) { + throw new \InvalidArgumentException('Package is not installed: '.$package); + } + + $downloadPath = $this->getInstallPath($package); + + $this->removeBinaries($package); + + $this->downloadManager->download($package, $downloadPath); + $this->installBinaries($package); + } + /** * {@inheritDoc} */ diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index 786c58ae5..d5a0e5230 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -15,6 +15,7 @@ namespace Composer\Package; use Composer\Package\LinkConstraint\LinkConstraintInterface; use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Repository\RepositoryInterface; +use Composer\Repository\PlatformRepository; /** * Base class for packages providing name storage and default match implementation @@ -134,6 +135,16 @@ abstract class BasePackage implements PackageInterface $this->repository = $repository; } + /** + * checks if this package is a platform package + * + * @return boolean + */ + public function isPlatform() + { + return $this->getRepository() instanceof PlatformRepository; + } + /** * Returns package unique name, constructed from name, version and release type. * diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php b/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php index 4bb58ded8..393261893 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v1/Installer/Custom.php @@ -14,5 +14,6 @@ class Custom implements InstallerInterface public function install(PackageInterface $package) {} public function update(PackageInterface $initial, PackageInterface $target) {} public function uninstall(PackageInterface $package) {} + public function replace(PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php b/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php index edd264428..b454cbcfd 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v2/Installer/Custom2.php @@ -14,5 +14,6 @@ class Custom2 implements InstallerInterface public function install(PackageInterface $package) {} public function update(PackageInterface $initial, PackageInterface $target) {} public function uninstall(PackageInterface $package) {} + public function replace(PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php b/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php index db211bed5..8e58c436e 100644 --- a/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php +++ b/tests/Composer/Test/Installer/Fixtures/installer-v3/Installer/Custom2.php @@ -14,5 +14,6 @@ class Custom2 implements InstallerInterface public function install(PackageInterface $package) {} public function update(PackageInterface $initial, PackageInterface $target) {} public function uninstall(PackageInterface $package) {} + public function replace(PackageInterface $package) {} public function getInstallPath(PackageInterface $package) {} } diff --git a/tests/Composer/Test/Installer/LibraryInstallerTest.php b/tests/Composer/Test/Installer/LibraryInstallerTest.php index ed655f983..0f85c4b21 100644 --- a/tests/Composer/Test/Installer/LibraryInstallerTest.php +++ b/tests/Composer/Test/Installer/LibraryInstallerTest.php @@ -175,6 +175,30 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase $library->uninstall($package); } + public function testReplace() + { + $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io); + $package = $this->createPackageMock(); + + $package + ->expects($this->once()) + ->method('getPrettyName') + ->will($this->returnValue('pkg')); + + $this->repository + ->expects($this->once()) + ->method('hasPackage') + ->with($package) + ->will($this->onConsecutiveCalls(true, false)); + + $this->dm + ->expects($this->once()) + ->method('download') + ->with($package, $this->vendorDir.'/pkg'); + + $library->replace($package); + } + public function testGetInstallPath() { $library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);