From eebffacd9f54c4527448434329765f845e8ee3ed Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 24 Apr 2014 16:41:42 +0200 Subject: [PATCH] Use pagination to get tags/branches from the github API --- src/Composer/Repository/Vcs/GitHubDriver.php | 47 +++++++++++++++----- src/Composer/Util/RemoteFilesystem.php | 16 +++++++ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 38c7869a5..0dc8a7eee 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -198,12 +198,17 @@ class GitHubDriver extends VcsDriver return $this->gitDriver->getTags(); } if (null === $this->tags) { - $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags'; - $tagsData = JsonFile::parseJson($this->getContents($resource), $resource); $this->tags = array(); - foreach ($tagsData as $tag) { - $this->tags[$tag['name']] = $tag['commit']['sha']; - } + $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags?per_page=100'; + + do { + $tagsData = JsonFile::parseJson($this->getContents($resource), $resource); + foreach ($tagsData as $tag) { + $this->tags[$tag['name']] = $tag['commit']['sha']; + } + + $resource = $this->getNextPage(); + } while ($resource); } return $this->tags; @@ -218,13 +223,18 @@ class GitHubDriver extends VcsDriver return $this->gitDriver->getBranches(); } if (null === $this->branches) { - $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads'; - $branchData = JsonFile::parseJson($this->getContents($resource), $resource); $this->branches = array(); - foreach ($branchData as $branch) { - $name = substr($branch['ref'], 11); - $this->branches[$name] = $branch['object']['sha']; - } + $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads?per_page=100'; + + do { + $branchData = JsonFile::parseJson($this->getContents($resource), $resource); + foreach ($branchData as $branch) { + $name = substr($branch['ref'], 11); + $this->branches[$name] = $branch['object']['sha']; + } + + $resource = $this->getNextPage(); + } while ($resource); } return $this->branches; @@ -428,4 +438,19 @@ class GitHubDriver extends VcsDriver ); $this->gitDriver->initialize(); } + + protected function getNextPage() + { + $headers = $this->remoteFilesystem->getLastHeaders(); + foreach ($headers as $header) { + if (substr($header, 0, 5) === 'Link:') { + $links = explode(',', substr($header, 5)); + foreach ($links as $link) { + if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) { + return $match[1]; + } + } + } + } + } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 106f61285..2f9dacf69 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -36,6 +36,7 @@ class RemoteFilesystem private $lastProgress; private $options; private $retryAuthFailure; + private $lastHeaders; /** * Constructor. @@ -91,6 +92,16 @@ class RemoteFilesystem return $this->options; } + /** + * Returns the headers of the last request + * + * @return array + */ + public function getLastHeaders() + { + return $this->lastHeaders; + } + /** * Get file content or copy action. * @@ -114,6 +125,7 @@ class RemoteFilesystem $this->progress = $progress; $this->lastProgress = null; $this->retryAuthFailure = true; + $this->lastHeaders = array(); // capture username/password from URL if there is one if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) { @@ -245,6 +257,10 @@ class RemoteFilesystem throw $e; } + if (!empty($http_response_header[0])) { + $this->lastHeaders = $http_response_header; + } + return $result; }