From 6a88d49ffb0389b9e659c163b12e6d944cfecef8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 27 Mar 2016 13:15:56 +0100 Subject: [PATCH] Add support for the new binary installer in PEAR installer, fixes #5117 --- src/Composer/Installer/BinaryInstaller.php | 53 ++++--- .../Installer/PearBinaryInstaller.php | 142 ++++++++++++++++++ src/Composer/Installer/PearInstaller.php | 107 +------------ 3 files changed, 177 insertions(+), 125 deletions(-) create mode 100644 src/Composer/Installer/PearBinaryInstaller.php diff --git a/src/Composer/Installer/BinaryInstaller.php b/src/Composer/Installer/BinaryInstaller.php index fea3905c3..b9f5b64e2 100644 --- a/src/Composer/Installer/BinaryInstaller.php +++ b/src/Composer/Installer/BinaryInstaller.php @@ -49,7 +49,7 @@ class BinaryInstaller public function installBinaries(PackageInterface $package, $installPath) { - $binaries = $package->getBinaries(); + $binaries = $this->getBinaries($package); if (!$binaries) { return; } @@ -92,6 +92,35 @@ class BinaryInstaller } } + public function removeBinaries(PackageInterface $package) + { + $this->initializeBinDir(); + + $binaries = $this->getBinaries($package); + if (!$binaries) { + return; + } + foreach ($binaries as $bin) { + $link = $this->binDir.'/'.basename($bin); + if (is_link($link) || file_exists($link)) { + $this->filesystem->unlink($link); + } + if (file_exists($link.'.bat')) { + $this->filesystem->unlink($link.'.bat'); + } + } + + // attempt removing the bin dir in case it is left empty + if ((is_dir($this->binDir)) && ($this->filesystem->isDirEmpty($this->binDir))) { + Silencer::call('rmdir', $this->binDir); + } + } + + protected function getBinaries(PackageInterface $package) + { + return $package->getBinaries(); + } + protected function installFullBinaries($binPath, $link, $bin, PackageInterface $package) { // add unixy support for cygwin and similar environments @@ -120,28 +149,6 @@ class BinaryInstaller file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link)); } - public function removeBinaries(PackageInterface $package) - { - $binaries = $package->getBinaries(); - if (!$binaries) { - return; - } - foreach ($binaries as $bin) { - $link = $this->binDir.'/'.basename($bin); - if (is_link($link) || file_exists($link)) { - $this->filesystem->unlink($link); - } - if (file_exists($link.'.bat')) { - $this->filesystem->unlink($link.'.bat'); - } - } - - // attempt removing the bin dir in case it is left empty - if ((is_dir($this->binDir)) && ($this->filesystem->isDirEmpty($this->binDir))) { - Silencer::call('rmdir', $this->binDir); - } - } - protected function initializeBinDir() { $this->filesystem->ensureDirectoryExists($this->binDir); diff --git a/src/Composer/Installer/PearBinaryInstaller.php b/src/Composer/Installer/PearBinaryInstaller.php new file mode 100644 index 000000000..c9e286a7a --- /dev/null +++ b/src/Composer/Installer/PearBinaryInstaller.php @@ -0,0 +1,142 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Installer; + +use Composer\IO\IOInterface; +use Composer\Package\PackageInterface; +use Composer\Util\Filesystem; +use Composer\Util\Platform; +use Composer\Util\ProcessExecutor; +use Composer\Util\Silencer; + +/** + * Utility to handle installation of package "bin"/binaries for PEAR packages + * + * @author Jordi Boggiano + */ +class PearBinaryInstaller extends BinaryInstaller +{ + private $installer; + + /** + * @param IOInterface $io + * @param string $binDir + * @param string $binCompat + * @param Filesystem $filesystem + */ + public function __construct(IOInterface $io, $binDir, $binCompat, Filesystem $filesystem, PearInstaller $installer) + { + parent::__construct($io, $binDir, $binCompat, $filesystem); + $this->installer = $installer; + } + + protected function getBinaries(PackageInterface $package) + { + $binariesPath = $this->installer->getInstallPath($package) . '/bin/'; + $binaries = array(); + if (file_exists($binariesPath)) { + foreach (new \FilesystemIterator($binariesPath, \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_FILEINFO) as $fileName => $value) { + if (!$value->isDir()) { + $binaries[] = 'bin/'.$fileName; + } + } + } + + return $binaries; + } + + protected function initializeBinDir() + { + parent::initializeBinDir(); + file_put_contents($this->binDir.'/composer-php', $this->generateUnixyPhpProxyCode()); + @chmod($this->binDir.'/composer-php', 0777); + file_put_contents($this->binDir.'/composer-php.bat', $this->generateWindowsPhpProxyCode()); + @chmod($this->binDir.'/composer-php.bat', 0777); + } + + protected function generateWindowsProxyCode($bin, $link) + { + $binPath = $this->filesystem->findShortestPath($link, $bin); + if ('.bat' === substr($bin, -4)) { + $caller = 'call'; + } else { + $handle = fopen($bin, 'r'); + $line = fgets($handle); + fclose($handle); + if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) { + $caller = trim($match[1]); + } else { + $caller = 'php'; + } + + if ($caller === 'php') { + return "@echo off\r\n". + "pushd .\r\n". + "cd %~dp0\r\n". + "set PHP_PROXY=%CD%\\composer-php.bat\r\n". + "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n". + "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n". + "popd\r\n". + "%PHP_PROXY% \"%BIN_TARGET%\" %*\r\n"; + } + } + + return "@echo off\r\n". + "pushd .\r\n". + "cd %~dp0\r\n". + "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n". + "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n". + "popd\r\n". + $caller." \"%BIN_TARGET%\" %*\r\n"; + } + + private function generateWindowsPhpProxyCode() + { + $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true); + + return + "@echo off\r\n" . + "setlocal enabledelayedexpansion\r\n" . + "set BIN_DIR=%~dp0\r\n" . + "set VENDOR_DIR=%BIN_DIR%\\".$binToVendor."\r\n" . + "set DIRS=.\r\n" . + "FOR /D %%V IN (%VENDOR_DIR%\\*) DO (\r\n" . + " FOR /D %%P IN (%%V\\*) DO (\r\n" . + " set DIRS=!DIRS!;%%~fP\r\n" . + " )\r\n" . + ")\r\n" . + "php.exe -d include_path=!DIRS! %*\r\n"; + } + + private function generateUnixyPhpProxyCode() + { + $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true); + + return + "#!/usr/bin/env sh\n". + "SRC_DIR=`pwd`\n". + "BIN_DIR=`dirname $0`\n". + "VENDOR_DIR=\$BIN_DIR/".escapeshellarg($binToVendor)."\n". + "DIRS=\"\"\n". + "for vendor in \$VENDOR_DIR/*; do\n". + " if [ -d \"\$vendor\" ]; then\n". + " for package in \$vendor/*; do\n". + " if [ -d \"\$package\" ]; then\n". + " DIRS=\"\${DIRS}:\${package}\"\n". + " fi\n". + " done\n". + " fi\n". + "done\n". + "php -d include_path=\".\$DIRS\" $@\n"; + } +} diff --git a/src/Composer/Installer/PearInstaller.php b/src/Composer/Installer/PearInstaller.php index 0e16fcb32..2ced5af6e 100644 --- a/src/Composer/Installer/PearInstaller.php +++ b/src/Composer/Installer/PearInstaller.php @@ -19,6 +19,7 @@ use Composer\Repository\InstalledRepositoryInterface; use Composer\Package\PackageInterface; use Composer\Util\Platform; use Composer\Util\ProcessExecutor; +use Composer\Util\Filesystem; /** * Package installation manager. @@ -37,7 +38,10 @@ class PearInstaller extends LibraryInstaller */ public function __construct(IOInterface $io, Composer $composer, $type = 'pear-library') { - parent::__construct($io, $composer, $type); + $filesystem = new Filesystem(); + $binaryInstaller = new PearBinaryInstaller($io, rtrim($composer->getConfig()->get('bin-dir'), '/'), $composer->getConfig()->get('bin-compat'), $filesystem, $this); + + parent::__construct($io, $composer, $type, $filesystem, $binaryInstaller); } /** @@ -52,7 +56,6 @@ class PearInstaller extends LibraryInstaller protected function installCode(PackageInterface $package) { parent::installCode($package); - parent::initializeBinDir(); $isWindows = Platform::isWindows(); $php_bin = $this->binDir . ($isWindows ? '/composer-php.bat' : '/composer-php'); @@ -79,104 +82,4 @@ class PearInstaller extends LibraryInstaller $this->io->writeError(' Cleaning up', true, IOInterface::VERBOSE); $this->filesystem->unlink($packageArchive); } - - protected function getBinaries(PackageInterface $package) - { - $binariesPath = $this->getInstallPath($package) . '/bin/'; - $binaries = array(); - if (file_exists($binariesPath)) { - foreach (new \FilesystemIterator($binariesPath, \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_FILEINFO) as $fileName => $value) { - if (!$value->isDir()) { - $binaries[] = 'bin/'.$fileName; - } - } - } - - return $binaries; - } - - protected function initializeBinDir() - { - parent::initializeBinDir(); - file_put_contents($this->binDir.'/composer-php', $this->generateUnixyPhpProxyCode()); - @chmod($this->binDir.'/composer-php', 0777); - file_put_contents($this->binDir.'/composer-php.bat', $this->generateWindowsPhpProxyCode()); - @chmod($this->binDir.'/composer-php.bat', 0777); - } - - protected function generateWindowsProxyCode($bin, $link) - { - $binPath = $this->filesystem->findShortestPath($link, $bin); - if ('.bat' === substr($bin, -4)) { - $caller = 'call'; - } else { - $handle = fopen($bin, 'r'); - $line = fgets($handle); - fclose($handle); - if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) { - $caller = trim($match[1]); - } else { - $caller = 'php'; - } - - if ($caller === 'php') { - return "@echo off\r\n". - "pushd .\r\n". - "cd %~dp0\r\n". - "set PHP_PROXY=%CD%\\composer-php.bat\r\n". - "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n". - "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n". - "popd\r\n". - "%PHP_PROXY% \"%BIN_TARGET%\" %*\r\n"; - } - } - - return "@echo off\r\n". - "pushd .\r\n". - "cd %~dp0\r\n". - "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n". - "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n". - "popd\r\n". - $caller." \"%BIN_TARGET%\" %*\r\n"; - } - - private function generateWindowsPhpProxyCode() - { - $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true); - - return - "@echo off\r\n" . - "setlocal enabledelayedexpansion\r\n" . - "set BIN_DIR=%~dp0\r\n" . - "set VENDOR_DIR=%BIN_DIR%\\".$binToVendor."\r\n" . - "set DIRS=.\r\n" . - "FOR /D %%V IN (%VENDOR_DIR%\\*) DO (\r\n" . - " FOR /D %%P IN (%%V\\*) DO (\r\n" . - " set DIRS=!DIRS!;%%~fP\r\n" . - " )\r\n" . - ")\r\n" . - "php.exe -d include_path=!DIRS! %*\r\n"; - } - - private function generateUnixyPhpProxyCode() - { - $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true); - - return - "#!/usr/bin/env sh\n". - "SRC_DIR=`pwd`\n". - "BIN_DIR=`dirname $0`\n". - "VENDOR_DIR=\$BIN_DIR/".escapeshellarg($binToVendor)."\n". - "DIRS=\"\"\n". - "for vendor in \$VENDOR_DIR/*; do\n". - " if [ -d \"\$vendor\" ]; then\n". - " for package in \$vendor/*; do\n". - " if [ -d \"\$package\" ]; then\n". - " DIRS=\"\${DIRS}:\${package}\"\n". - " fi\n". - " done\n". - " fi\n". - "done\n". - "php -d include_path=\".\$DIRS\" $@\n"; - } }