From 224934831dbe1a8985556c3b161823d6afbffd95 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 5 Dec 2012 19:20:36 +0100 Subject: [PATCH] Change all github archive URLs to API URLs and handle fallback for those to nodeload --- src/Composer/Downloader/ArchiveDownloader.php | 24 +++++---- src/Composer/Downloader/FileDownloader.php | 20 +++---- src/Composer/Repository/Vcs/GitHubDriver.php | 9 +--- .../Test/Downloader/ArchiveDownloaderTest.php | 53 +++++++++++++++++++ .../Test/Repository/Vcs/GitHubDriverTest.php | 8 +-- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 917fe56e2..b8fc32c7d 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -93,20 +93,26 @@ abstract class ArchiveDownloader extends FileDownloader */ protected function processUrl(PackageInterface $package, $url) { - // support for legacy github archives - if ($package->getDistReference() && preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) { - $url = 'https://github.com/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference(); - } - - if ($package->getDistReference() && preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar\.gz)$}i', $url, $match)) { - $url = 'https://github.com/' . $match[1] . '/'. $match[2] . '/archive/' . $package->getDistReference() . '.' . $match[3]; + if ($package->getDistReference() && strpos($url, 'github.com')) { + if (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) { + // update legacy github archives to API calls with the proper reference + $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference(); + } elseif ($package->getDistReference() && preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) { + // update current github web archives to API calls with the proper reference + $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference(); + } elseif ($package->getDistReference() && preg_match('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) { + // update api archives to the proper reference + $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference(); + } } if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) { // bypass https for github if openssl is disabled - if (preg_match('{^https?://github.com/([^/]+/[^/]+)/(zip|tar)ball/([^/]+)$}i', $url, $match)) { + if (preg_match('{^https://api\.github\.com/repos/([^/]+/[^/]+)/(zip|tar)ball/([^/]+)$}i', $url, $match)) { $url = 'http://nodeload.github.com/'.$match[1].'/'.$match[2].'/'.$match[3]; - } elseif (preg_match('{^https?://github.com/([^/]+/[^/]+)/archive/([^/]+)\.(zip|tar\.gz)$}i', $url, $match)) { + } elseif (preg_match('{^https://github\.com/([^/]+/[^/]+)/(zip|tar)ball/([^/]+)$}i', $url, $match)) { + $url = 'http://nodeload.github.com/'.$match[1].'/'.$match[2].'/'.$match[3]; + } elseif (preg_match('{^https://github\.com/([^/]+/[^/]+)/archive/([^/]+)\.(zip|tar\.gz)$}i', $url, $match)) { $url = 'http://nodeload.github.com/'.$match[1].'/'.$match[3].'/'.$match[2]; } else { throw new \RuntimeException('You must enable the openssl extension to download files via https'); diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 220018ae0..384e7c735 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -84,31 +84,31 @@ class FileDownloader implements DownloaderInterface $this->io->write(" - Installing " . $package->getName() . " (" . VersionParser::formatVersion($package) . ")"); - $processUrl = $this->processUrl($package, $url); - $processHost = parse_url($processUrl, PHP_URL_HOST); + $processedUrl = $this->processUrl($package, $url); + $hostname = parse_url($processedUrl, PHP_URL_HOST); - if (strpos($processHost, 'github.com') === (strlen($processHost) - 10)) { - $processHost = 'github.com'; + if (strpos($hostname, 'github.com') === (strlen($hostname) - 10)) { + $hostname = 'github.com'; } try { try { if (!$this->cache || !$this->cache->copyTo($this->getCacheKey($package), $fileName)) { - $this->rfs->copy(parse_url($processUrl, PHP_URL_HOST), $processUrl, $fileName); + $this->rfs->copy(parse_url($processedUrl, PHP_URL_HOST), $processedUrl, $fileName); if ($this->cache) { $this->cache->copyFrom($this->getCacheKey($package), $fileName); } } } catch (TransportException $e) { - if (404 === $e->getCode() && 'github.com' === $processHost) { - $message = "\n".'Could not fetch '.$processUrl.', enter your GitHub credentials to access private repos'; + if (404 === $e->getCode() && 'github.com' === $hostname) { + $message = "\n".'Could not fetch '.$processedUrl.', enter your GitHub credentials to access private repos'; $gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs); - if (!$gitHubUtil->authorizeOAuth($processHost) - && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($processHost, $message)) + if (!$gitHubUtil->authorizeOAuth($hostname) + && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($hostname, $message)) ) { throw $e; } - $this->rfs->copy($processHost, $processUrl, $fileName); + $this->rfs->copy($hostname, $processedUrl, $fileName); } else { throw $e; } diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 0b5a32294..1a65bb702 100755 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -108,14 +108,7 @@ class GitHubDriver extends VcsDriver return $this->gitDriver->getDist($identifier); } $label = array_search($identifier, $this->getTags()) ?: $identifier; - - if ($this->isPrivate) { - // Private GitHub repository zipballs are accessed through the API. - // http://developer.github.com/v3/repos/contents/#get-archive-link - $url = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$label; - } else { - $url = 'https://github.com/'.$this->owner.'/'.$this->repository.'/archive/'.$label.'.zip'; - } + $url = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$label; return array('type' => 'zip', 'url' => $url, 'reference' => $label, 'shasum' => ''); } diff --git a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php index 74e76d85d..9fd1efb0d 100644 --- a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php @@ -62,4 +62,57 @@ class ArchiveDownloaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals('http://nodeload.github.com/composer/composer/tar.gz/master', $url); } } + + public function testProcessUrl3() + { + $downloader = $this->getMockForAbstractClass('Composer\Downloader\ArchiveDownloader', array($this->getMock('Composer\IO\IOInterface'), $this->getMock('Composer\Config'))); + $method = new \ReflectionMethod($downloader, 'processUrl'); + $method->setAccessible(true); + + $expected = 'https://api.github.com/repos/composer/composer/zipball/master'; + $url = $method->invoke($downloader, $this->getMock('Composer\Package\PackageInterface'), $expected); + + if (extension_loaded('openssl')) { + $this->assertEquals($expected, $url); + } else { + $this->assertEquals('http://nodeload.github.com/composer/composer/zip/master', $url); + } + } + + /** + * @dataProvider provideUrls + */ + public function testProcessUrlRewriteDist($url) + { + $downloader = $this->getMockForAbstractClass('Composer\Downloader\ArchiveDownloader', array($this->getMock('Composer\IO\IOInterface'), $this->getMock('Composer\Config'))); + $method = new \ReflectionMethod($downloader, 'processUrl'); + $method->setAccessible(true); + + $type = strpos($url, 'tar') ? 'tar' : 'zip'; + $expected = 'https://api.github.com/repos/composer/composer/'.$type.'ball/ref'; + + $package = $this->getMock('Composer\Package\PackageInterface'); + $package->expects($this->any()) + ->method('getDistReference') + ->will($this->returnValue('ref')); + $url = $method->invoke($downloader, $package, $url); + + if (extension_loaded('openssl')) { + $this->assertEquals($expected, $url); + } else { + $this->assertEquals('http://nodeload.github.com/composer/composer/'.$type.'/ref', $url); + } + } + + public function provideUrls() + { + return array( + array('https://api.github.com/repos/composer/composer/zipball/master'), + array('https://api.github.com/repos/composer/composer/tarball/master'), + array('https://github.com/composer/composer/zipball/master'), + array('https://www.github.com/composer/composer/tarball/master'), + array('https://github.com/composer/composer/archive/master.zip'), + array('https://github.com/composer/composer/archive/master.tar.gz'), + ); + } } diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 95d94eeec..c8122c7da 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -155,7 +155,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($identifier); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/archive/v0.0.0.zip', $dist['url']); + $this->assertEquals('https://api.github.com/repos/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($identifier); @@ -165,7 +165,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($sha); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/archive/v0.0.0.zip', $dist['url']); + $this->assertEquals('https://api.github.com/repos/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($sha); @@ -217,7 +217,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($identifier); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/archive/feature/3.2-foo.zip', $dist['url']); + $this->assertEquals('https://api.github.com/repos/composer/packagist/zipball/feature/3.2-foo', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($identifier); @@ -227,7 +227,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($sha); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/archive/feature/3.2-foo.zip', $dist['url']); + $this->assertEquals('https://api.github.com/repos/composer/packagist/zipball/feature/3.2-foo', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($sha);