Browse Source

Use pagination to get tags/branches from the github API

Jordi Boggiano 11 years ago
parent
commit
eebffacd9f
2 changed files with 52 additions and 11 deletions
  1. 36 11
      src/Composer/Repository/Vcs/GitHubDriver.php
  2. 16 0
      src/Composer/Util/RemoteFilesystem.php

+ 36 - 11
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];
+                    }
+                }
+            }
+        }
+    }
 }

+ 16 - 0
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;
     }