From fa613cad1946a91622694ff8927e60f478e5f171 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Wed, 8 Jun 2011 22:06:57 +0200 Subject: [PATCH] Rewrite PearRepository to implement PEAR Client/Server protocol itself, taking longer then pear remote-list, but at least showing ALL available versions, making arbitrary dependencies possible. --- .../Downloader/AbstractDownloader.php | 8 +- src/Composer/Downloader/PearDownloader.php | 2 +- src/Composer/Repository/PearRepository.php | 110 ++++++++++++------ 3 files changed, 78 insertions(+), 42 deletions(-) diff --git a/src/Composer/Downloader/AbstractDownloader.php b/src/Composer/Downloader/AbstractDownloader.php index 3d5cb08e6..3104be3f5 100644 --- a/src/Composer/Downloader/AbstractDownloader.php +++ b/src/Composer/Downloader/AbstractDownloader.php @@ -20,7 +20,7 @@ use Composer\Package\PackageInterface; */ abstract class AbstractDownloader { - protected function downloadFile ($url, $path) + protected function downloadFile($url, $path) { $file = fopen($url, "rb"); if ($file) { @@ -29,13 +29,9 @@ abstract class AbstractDownloader while (!feof($file)) { fwrite($newf, fread($file, 1024 * 8), 1024 * 8); } + fclose($newf); } - } - if ($file) { fclose($file); } - if ($newf) { - fclose($newf); - } } } \ No newline at end of file diff --git a/src/Composer/Downloader/PearDownloader.php b/src/Composer/Downloader/PearDownloader.php index 5ef405cea..1cce75632 100644 --- a/src/Composer/Downloader/PearDownloader.php +++ b/src/Composer/Downloader/PearDownloader.php @@ -30,7 +30,7 @@ class PearDownloader extends AbstractDownloader throw new \UnexpectedValueException($path.' does not exist and could not be created.'); } } - + $tmpName = tempnam(sys_get_temp_dir(), ''); $this->downloadFile($package->getSourceUrl(), $tmpName); diff --git a/src/Composer/Repository/PearRepository.php b/src/Composer/Repository/PearRepository.php index f713ef7e0..18832759c 100644 --- a/src/Composer/Repository/PearRepository.php +++ b/src/Composer/Repository/PearRepository.php @@ -25,52 +25,92 @@ class PearRepository extends ArrayRepository private $name; private $url; - public function __construct($url, $name) + public function __construct($url) { $this->url = $url; - $this->name = $name; - + if (!filter_var($this->url, FILTER_VALIDATE_URL)) { throw new \UnexpectedValueException("Invalid url given for PEAR repository " . $name); } } + + /** + * @param string $url + * @return DOMDocument + */ + private function requestXml($url) + { + $content = file_get_contents($url); + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->loadXML($content); + + return $dom; + } protected function initialize() { parent::initialize(); - - exec("pear remote-list -c ".escapeshellarg($this->name), $output, $return); - - if ($return != 0) { - throw new \BadMethodCallException("Could not execute pear channel-list, an error occured."); - } - - $headersDone = false; - foreach ($output AS $line) { - $parts = explode(" ", preg_replace('(\s{2,})', ' ', trim($line))); - if (count($parts) != 2) { - continue; - } - list($packageName, $pearVersion) = $parts; - - if (!$headersDone) { - if ($packageName == "PACKAGE" && $pearVersion == "VERSION") { - $headersDone = true; - } - continue; - } - - if ($pearVersion == "-n/a-") { - continue; // Preferred stability is set to a level that this package can't fullfil. - } - - $version = BasePackage::parseVersion($pearVersion); - $package = new MemoryPackage($packageName, $version['version'], $version['type']); - $package->setSourceType('pear'); - $package->setSourceUrl($this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"); - - $this->addPackage($package); + set_error_handler(function($severity, $message, $file, $line) { + throw new ErrorException($message, $severity, $severity, $file, $line); + }); + try { + $this->fetchFromServer(); + } catch(ErrorException $e) { + + } + restore_error_handler(); + } + + protected function fetchFromServer() + { + $categoryXML = $this->requestXml($this->url . "/rest/c/categories.xml"); + $categories = $categoryXML->getElementsByTagName("c"); + + foreach ($categories as $category) { + $categoryLink = $category->getAttribute("xlink:href"); + $categoryLink = str_replace("info.xml", "packages.xml", $categoryLink); + $packagesXML = $this->requestXml($this->url . $categoryLink); + + $packages = $packagesXML->getElementsByTagName('p'); + foreach ($packages as $package) { + $packageName = $package->nodeValue; + + $packageLink = $package->getAttribute('xlink:href'); + $releaseLink = $this->url . str_replace("/rest/p/", "/rest/r/", $packageLink); + $allReleasesLink = $releaseLink . "/allreleases2.xml"; + $releasesXML = $this->requestXml($allReleasesLink); + + $releases = $releasesXML->getElementsByTagName('r'); + + foreach ($releases as $release) { + /* @var $release DOMElement */ + $pearVersion = $release->getElementsByTagName('v')->item(0)->nodeValue; + + $version = BasePackage::parseVersion($pearVersion); + + $package = new MemoryPackage($packageName, $version['version'], $version['type']); + $package->setSourceType('pear'); + $package->setSourceUrl($this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"); + + $depsLink = $releaseLink . "/deps.".$pearVersion.".txt"; + $deps = file_get_contents($depsLink); + if (preg_match('((O:([0-9])+:"([^"]+)"))', $deps, $matches)) { + if (strlen($matches[3]) == $matches[2]) { + throw new \InvalidArgumentException("Invalid dependency data, it contains serialized objects."); + } + } + $deps = unserialize($deps); + if (isset($deps['required']['package'])) { + foreach ($deps['required']['package'] as $dependency) { + $requires[$dependency['name']] = $dependency['min']; + } + $package->setRequires($requires); + } + + $this->addPackage($package); + } + } } } }