/** * If composer tries to install into a non-empty folder, we risk to effectively erase an existing installation. * This is not a composer limitation we can fix - it happens because composer might be using git to download the * sources, and git can not clone a repo into a non-empty folder. * * To prevent this, we adopt the following strategy: * - install in a separate, temporary directory * - then move over the installed files copying on top of the existing installation * * @param InstalledRepositoryInterface $repo * @param PackageInterface $package */ public function install( InstalledRepositoryInterface $repo, PackageInterface $package ) { $downloadPath = $this->getInstallPath( $package ); $fileSystem = new Filesystem(); if ( !is_dir( $downloadPath ) || $fileSystem->isDirEmpty( $downloadPath ) ) { return parent::install( $repo, $package ); } $actualLegacyDir = $this->ezpublishLegacyDir; $this->ezpublishLegacyDir = $this->generateTempDirName(); if ( $this->io->isVerbose() ) { $this->io->write( "Installing in temporary directory." ); } parent::install( $repo, $package ); /// @todo the following function does not warn of any failures in copying stuff over. We should probably fix it... if ( $this->io->isVerbose() ) { $this->io->write( "Updating new code over existing installation." ); } $fileSystem->copyThenRemove( $this->ezpublishLegacyDir, $actualLegacyDir ); // if parent::install installed binaries, then the resulting shell/bat stubs will not work. We have to redo them $this->removeBinaries( $package ); $this->ezpublishLegacyDir = $actualLegacyDir; $this->installBinaries( $package ); }
/** * Isolated event that runs on PRE hooks to cleanup mapped packages */ public function staticsCleanup(Event $event) { foreach ($this->getStaticPackages() as $package) { foreach ($this->getStaticMaps($package->getName()) as $mappingDir => $mappings) { $themeRootDir = $this->getRootThemeDir($mappingDir); if (!is_dir($themeRootDir)) { continue; } // Get contents and sort $contents = $this->getFullDirectoryListing($themeRootDir); $strLengths = array_map('strlen', $contents); array_multisort($strLengths, SORT_DESC, $contents); // Exception error message $errorMsg = sprintf("<error>Failed to remove %s from %s</error>", $package->getName(), $themeRootDir); foreach ($contents as $content) { // Remove packages symlinked files/dirs if (is_link($content)) { $this->tryCleanup($content, $errorMsg); continue; } // Remove empty folders if (is_dir($content) && $this->filesystem->isDirEmpty($content)) { $this->tryCleanup($content, $errorMsg); } } } } }
/** * @param CommandEvent $event * @return bool|void */ public function staticsCleanup(CommandEvent $event) { foreach ($this->getStaticPackages() as $package) { foreach ($this->getStaticMaps($package->getName()) as $mappingDir => $mappings) { $mappingDirs = explode('/', $mappingDir); $packageRootDir = sprintf('%s/%s/skin/frontend/%s', getcwd(), $this->mageDir, $mappingDirs[0]); $themeRootDir = sprintf('%s/%s/skin/frontend/%s', getcwd(), $this->mageDir, $mappingDir); if (!is_dir($themeRootDir)) { continue; } // Get contents and sort $contents = $this->getFullDirectoryListing($themeRootDir); $strLengths = array_map('strlen', $contents); array_multisort($strLengths, SORT_DESC, $contents); // Exception error message $errorMsg = sprintf("<error>Failed to remove %s from %s</error>", $package->getName(), $packageRootDir); foreach ($contents as $content) { // Remove packages symlinked files/dirs if (is_link($content) && strpos($content, $mappingDir) !== false) { $this->tryCleanup($content, $errorMsg); continue; } // Remove empty folders if (is_dir($content) && $this->filesystem->isDirEmpty($content)) { $this->tryCleanup($content, $errorMsg); } } // Check if we need to remove package dir if (is_dir($packageRootDir) && $this->filesystem->isDirEmpty($packageRootDir)) { $this->tryCleanup(rtrim($packageRootDir, "/"), $errorMsg); } } } }
/** * UnInstall the extension given the list of install files * * @param array $files */ public function unInstall(array $files) { foreach ($files as $file) { $file = $this->rootDir . $file; /* because of different reasons the file can be already gone. example: - file got deployed by multiple modules(should only happen with copy force) - user did things when the file is a symlink, but the target is already gone, file_exists returns false */ if (file_exists($file) xor is_link($file)) { $this->fileSystem->unlink($file); $parentDir = dirname($file); while ($this->fileSystem->isDirEmpty($parentDir) && $parentDir !== $this->rootDir) { $this->fileSystem->removeDirectory($parentDir); $parentDir = dirname($parentDir); } } } }
/** * @param string $source * @param string $destination */ public function unInstall($source, $destination) { $iterator = $this->getIterator($source, RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $item) { $destinationFile = sprintf("%s/%s", $destination, $iterator->getSubPathName()); if ($this->exclude->exclude($iterator->getSubPathName())) { continue; } if (!file_exists($destinationFile)) { $this->gitIgnore->removeEntry($iterator->getSubPathName()); continue; } if ($item->isDir()) { //check if there are not other files in this dir if ($this->fileSystem->isDirEmpty($destinationFile)) { $this->fileSystem->removeDirectory($destinationFile); } continue; } $this->fileSystem->unlink($destinationFile); $this->gitIgnore->removeEntry('/' . $iterator->getSubPathName()); } $this->gitIgnore->removeIgnoreDirectories(); }
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) { $downloadPath = $this->getInstallPath($package); $fileSystem = new Filesystem(); $actualLegacyDir = $this->innomaticLegacyDir; $this->innomaticLegacyDir = $this->generateTempDirName(); if (!is_dir($downloadPath) || $fileSystem->isDirEmpty($downloadPath)) { if ($this->io->isVerbose()) { $this->io->write("Installing in temporary directory."); } parent::install($repo, $package); if ($this->io->isVerbose()) { $this->io->write("Copying to the Innomatic legacy directory."); } $fileSystem->copyThenRemove($this->innomaticLegacyDir . '/source/', $actualLegacyDir); $this->innomaticLegacyDir = $actualLegacyDir; } }
/** * {@inheritdoc} */ public function install(InstalledRepositoryInterface $repo, PackageInterface $package) { $installPath = $this->getInstallPath($package); if (!is_dir($installPath) || $this->fileSystem->isDirEmpty($installPath)) { return parent::install($repo, $package); } $actualRootDir = $this->rubedoRootDir; $this->rubedoRootDir = $this->generateTempDir(); if ($this->io->isVerbose()) { $this->io->write("Installing in temporary directory."); } parent::install($repo, $package); // Retrieving previous package version $oldPkg = false; foreach ($repo->getPackages() as $installedPkg) { if ($installedPkg->getName() == $package->getName()) { $oldPkg = $installedPkg; } } // Retrieving list of package files removed from previous installed version $removedFiles = $oldPkg ? $this->getRemovedFiles($package, $oldPkg) : array(); $this->installRubedoCoreSources($actualRootDir, $removedFiles); }
public function installProject(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false, InputInterface $input) { $oldCwd = getcwd(); // we need to manually load the configuration to pass the auth credentials to the io interface! $io->loadConfiguration($config); if ($packageName !== null) { $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disablePlugins, $noScripts, $keepVcs, $noProgress); } else { $installedFromVcs = false; } $composer = Factory::create($io, null, $disablePlugins); $composer->getDownloadManager()->setOutputProgress(!$noProgress); $fs = new Filesystem(); if ($noScripts === false) { // dispatch event $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages); } $rootPackageConfig = $composer->getConfig(); $this->updatePreferredOptions($rootPackageConfig, $input, $preferSource, $preferDist); // install dependencies of the created project if ($noInstall === false) { $installer = Installer::create($io, $composer); $installer->setPreferSource($preferSource)->setPreferDist($preferDist)->setDevMode($installDevPackages)->setRunScripts(!$noScripts)->setIgnorePlatformRequirements($ignorePlatformReqs); if ($disablePlugins) { $installer->disablePlugins(); } $status = $installer->run(); if (0 !== $status) { return $status; } } $hasVcs = $installedFromVcs; if (!$keepVcs && $installedFromVcs && (!$io->isInteractive() || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true))) { $finder = new Finder(); $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false); foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) { $finder->name($vcsName); } try { $dirs = iterator_to_array($finder); unset($finder); foreach ($dirs as $dir) { if (!$fs->removeDirectory($dir)) { throw new \RuntimeException('Could not remove ' . $dir); } } } catch (\Exception $e) { $io->writeError('<error>An error occurred while removing the VCS metadata: ' . $e->getMessage() . '</error>'); } $hasVcs = false; } // rewriting self.version dependencies with explicit version numbers if the package's vcs metadata is gone if (!$hasVcs) { $package = $composer->getPackage(); $configSource = new JsonConfigSource(new JsonFile('composer.json')); foreach (BasePackage::$supportedLinkTypes as $type => $meta) { foreach ($package->{'get' . $meta['method']}() as $link) { if ($link->getPrettyConstraint() === 'self.version') { $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion()); } } } } if ($noScripts === false) { // dispatch event $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages); } chdir($oldCwd); $vendorComposerDir = $composer->getConfig()->get('vendor-dir') . '/composer'; if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) { @rmdir($vendorComposerDir); $vendorDir = $composer->getConfig()->get('vendor-dir'); if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) { @rmdir($vendorDir); } } return 0; }
/** * Uninstalls NodeJS. * Note: other classes cannot be loaded here since the package has already been removed. */ private function onUninstall($binDir, $targetDir) { $fileSystem = new Filesystem(); if (file_exists($targetDir)) { $this->verboseLog("Removing NodeJS local install"); // Let's remove target directory $fileSystem->remove($targetDir); $vendorNodeDir = dirname($targetDir); if ($fileSystem->isDirEmpty($vendorNodeDir)) { $fileSystem->remove($vendorNodeDir); } } // Now, let's remove the links $this->verboseLog("Removing NodeJS and NPM links from Composer bin directory"); foreach (array("node", "npm", "node.bat", "npm.bat") as $file) { $realFile = $binDir . DIRECTORY_SEPARATOR . $file; if (file_exists($realFile)) { $fileSystem->remove($realFile); } } }