Kaynağa Gözat

Implement HTTPGitClient._read_references.

Jelmer Vernooij 13 yıl önce
ebeveyn
işleme
d67ecb3735
2 değiştirilmiş dosya ile 46 ekleme ve 20 silme
  1. 39 16
      dulwich/client.py
  2. 7 4
      dulwich/tests/compat/test_client.py

+ 39 - 16
dulwich/client.py

@@ -24,6 +24,7 @@ __docformat__ = 'restructuredText'
 import select
 import socket
 import subprocess
+import urllib2
 import urlparse
 
 from dulwich.errors import (
@@ -77,6 +78,19 @@ class GitClient(object):
         if thin_packs:
             self._fetch_capabilities.append('thin-pack')
 
+    def _read_refs(self, proto):
+        server_capabilities = None
+        refs = {}
+        # Receive refs from server
+        for pkt in proto.read_pkt_seq():
+            (sha, ref) = pkt.rstrip('\n').split(' ', 1)
+            if sha == 'ERR':
+                raise GitProtocolError(ref)
+            if server_capabilities is None:
+                (ref, server_capabilities) = extract_capabilities(ref)
+            refs[ref] = sha
+        return refs, server_capabilities
+
     def send_pack(self, path, determine_wants, generate_pack_contents):
         """Upload a pack to a remote repository.
 
@@ -138,19 +152,6 @@ class TraditionalGitClient(GitClient):
         """
         raise NotImplementedError()
 
-    def _read_refs(self, proto):
-        server_capabilities = None
-        refs = {}
-        # Receive refs from server
-        for pkt in proto.read_pkt_seq():
-            (sha, ref) = pkt.rstrip('\n').split(' ', 1)
-            if sha == 'ERR':
-                raise GitProtocolError(ref)
-            if server_capabilities is None:
-                (ref, server_capabilities) = extract_capabilities(ref)
-            refs[ref] = sha
-        return refs, server_capabilities
-
     def _parse_status_report(self, proto):
         unpack = proto.read_pkt_line().strip()
         if unpack != 'unpack ok':
@@ -416,11 +417,16 @@ class SSHGitClient(TraditionalGitClient):
 
 class HttpGitClient(GitClient):
 
-    def __init__(self, host, port=None, username=None, force_dumb=False, *args, **kwargs):
+    def __init__(self, host, port=None, username=None, password=None, dumb=None, *args, **kwargs):
         self.host = host
         self.port = port
-        self.force_dumb = force_dumb
+        self.dumb = dumb
         self.username = username
+        self.password = password
+        netloc = self.host
+        if self.port:
+            netloc += ":%d" % self.port
+        self.url = "http://%s/" % netloc
         GitClient.__init__(self, *args, **kwargs)
 
     @classmethod
@@ -428,7 +434,17 @@ class HttpGitClient(GitClient):
         parsed = urlparse.urlparse(url)
         assert parsed.scheme == 'http'
         return cls(parsed.hostname, port=parsed.port, username=parsed.port,
-                   password=parsed.password)
+                   password=parsed.password), parsed.path
+
+    def _discover_references(self, service, url):
+        url = urlparse.urljoin(url+"/", "info/refs")
+        if not self.dumb:
+            url += "?service=%s" % service
+        req = urllib2.Request(url)
+        resp = urllib2.urlopen(req)
+        self.dumb = (not resp.info().gettype().startswith("application/x-git-"))
+        proto = Protocol(resp.read, None, report_activity=self._report_activity)
+        return self._read_refs(proto)
 
     def send_pack(self, path, determine_wants, generate_pack_contents):
         """Upload a pack to a remote repository.
@@ -441,6 +457,8 @@ class HttpGitClient(GitClient):
         :raises UpdateRefsError: if the server supports report-status
                                  and rejects ref updates
         """
+        url = urlparse.urljoin(self.url, path)
+        refs, server_capabilities = self._discover_references("git-upload-pack", url)
         raise NotImplementedError(self.send_pack)
 
     def fetch_pack(self, path, determine_wants, graph_walker, pack_data,
@@ -452,6 +470,8 @@ class HttpGitClient(GitClient):
         :param pack_data: Callback called for each bit of data in the pack
         :param progress: Callback for progress reports (strings)
         """
+        url = urlparse.urljoin(self.url, path)
+        refs, server_capabilities = self._discover_references("git-receive-pack", url)
         raise NotImplementedError(self.fetch_pack)
 
 
@@ -467,6 +487,9 @@ def get_transport_and_path(uri):
     elif parsed.scheme == 'git+ssh':
         return SSHGitClient(parsed.hostname, port=parsed.port,
                             username=parsed.username), parsed.path
+    elif parsed.scheme == 'http':
+        return HttpGitClient(parsed.hostname, port=parsed.port,
+                             username=parsed.username), parsed.path
 
     if parsed.scheme and not parsed.netloc:
         # SSH with no user@, zero or one leading slash.

+ 7 - 4
dulwich/tests/compat/test_client.py

@@ -30,6 +30,7 @@ import subprocess
 import tempfile
 import threading
 import urllib
+import urlparse
 
 from dulwich import (
     client,
@@ -296,6 +297,7 @@ class GitHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
         env['SERVER_PROTOCOL'] = self.protocol_version
         env['SERVER_PORT'] = str(self.server.server_port)
         env['GIT_PROJECT_ROOT'] = self.server.root_path
+        env["GIT_HTTP_EXPORT_ALL"] = "1"
         env['REQUEST_METHOD'] = self.command
         uqrest = urllib.unquote(rest)
         env['PATH_INFO'] = uqrest
@@ -369,7 +371,7 @@ class GitHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
         while select.select([self.rfile._sock], [], [], 0)[0]:
             if not self.rfile._sock.recv(1):
                 break
-        args = ['http-backend']
+        args = ['-c', 'http.uploadpack=true', '-c', 'http.receivepack=true', 'http-backend']
         if '=' not in decoded_query:
             args.append(decoded_query)
         stdout = run_git_or_fail(args, input=data, env=env, stderr=subprocess.PIPE)
@@ -405,7 +407,7 @@ class DulwichHttpClientTest(CompatTestCase, DulwichClientTestBase):
     def setUp(self):
         CompatTestCase.setUp(self)
         DulwichClientTestBase.setUp(self)
-        self._httpd = HTTPGitServer(("localhost", 8080), self.gitroot)
+        self._httpd = HTTPGitServer(("localhost", 0), self.gitroot)
         self.addCleanup(self._httpd.shutdown)
         threading.Thread(target=self._httpd.serve_forever).start()
 
@@ -414,7 +416,8 @@ class DulwichHttpClientTest(CompatTestCase, DulwichClientTestBase):
         CompatTestCase.tearDown(self)
 
     def _client(self):
-        return client.HttpGitClient(self._httpd.get_url())
+        ret, self._path = client.HttpGitClient.from_url(self._httpd.get_url())
+        return ret
 
     def _build_path(self, path):
-        return path
+        return urlparse.urljoin(self._path.strip("/"), path.strip("/"))