Browse Source

Support opening git repositories by path.

Jelmer Vernooij 15 years ago
parent
commit
b8cde0e0b1
4 changed files with 51 additions and 22 deletions
  1. 2 2
      bin/dul-daemon
  2. 2 2
      bin/dul-web
  3. 35 11
      dulwich/server.py
  4. 12 7
      dulwich/tests/test_server.py

+ 2 - 2
bin/dul-daemon

@@ -19,13 +19,13 @@
 
 import sys
 from dulwich.repo import Repo
-from dulwich.server import GitBackend, TCPGitServer
+from dulwich.server import DictBackend, GitBackendRepo, TCPGitServer
 
 if __name__ == "__main__":
     gitdir = None
     if len(sys.argv) > 1:
         gitdir = sys.argv[1]
 
-    backend = GitBackend(Repo(gitdir))
+	backend = DictBackend({"/": GitBackendRepo(Repo(gitdir))})
     server = TCPGitServer(backend, 'localhost')
     server.serve_forever()

+ 2 - 2
bin/dul-web

@@ -20,7 +20,7 @@
 import os
 import sys
 from dulwich.repo import Repo
-from dulwich.server import GitBackend
+from dulwich.server import GitBackendRepo, DictBackend
 from dulwich.web import HTTPGitApplication
 from wsgiref.simple_server import make_server
 
@@ -30,7 +30,7 @@ if __name__ == "__main__":
     else:
         gitdir = os.getcwd()
 
-    backend = GitBackend(Repo(gitdir))
+	backend = DictBackend({"/": GitBackendRepo(Repo(gitdir))})
     app = HTTPGitApplication(backend)
     # TODO: allow serving on other ports via command-line flag
     server = make_server('', 8000, app)

+ 35 - 11
dulwich/server.py

@@ -56,6 +56,17 @@ from dulwich.pack import (
 class Backend(object):
     """A backend for the Git smart server implementation."""
 
+    def open_repository(self, path):
+        """Open the repository at a path."""
+        raise NotImplementedError(self.open_repository)
+
+
+class BackendRepo(object):
+    """Repository abstraction used by the Git server.
+    
+    Eventually this should become just a subset of Repo.
+    """
+
     def get_refs(self):
         """
         Get all the refs in the repository
@@ -85,7 +96,7 @@ class Backend(object):
         raise NotImplementedError
 
 
-class GitBackend(Backend):
+class GitBackendRepo(BackendRepo):
 
     def __init__(self, repo):
         self.repo = repo
@@ -149,6 +160,17 @@ class GitBackend(Backend):
         return status
 
 
+class DictBackend(Backend):
+    """Trivial backend that looks up Git repositories in a dictionary."""
+
+    def __init__(self, repos):
+        self.repos = repos
+
+    def open_repository(self, path):
+        # FIXME: What to do in case there is no repo ?
+        return self.repos[path]
+
+
 class Handler(object):
     """Smart protocol command handler base class."""
 
@@ -196,6 +218,7 @@ class UploadPackHandler(Handler):
     def __init__(self, backend, args, read, write,
                  stateless_rpc=False, advertise_refs=False):
         Handler.__init__(self, backend, read, write)
+        self.repo = backend.open_repository(args[0])
         self._graph_walker = None
         self.stateless_rpc = stateless_rpc
         self.advertise_refs = advertise_refs
@@ -225,14 +248,14 @@ class UploadPackHandler(Handler):
         if not self.has_capability("include-tag"):
             return {}
         if refs is None:
-            refs = self.backend.get_refs()
+            refs = self.repo.get_refs()
         if repo is None:
-            repo = getattr(self.backend, "repo", None)
+            repo = getattr(self.repo, "repo", None)
             if repo is None:
                 # Bail if we don't have a Repo available; this is ok since
                 # clients must be able to handle if the server doesn't include
                 # all relevant tags.
-                # TODO: either guarantee a Repo, or fix behavior when missing
+                # TODO: fix behavior when missing
                 return {}
         tagged = {}
         for name, sha in refs.iteritems():
@@ -244,8 +267,8 @@ class UploadPackHandler(Handler):
     def handle(self):
         write = lambda x: self.proto.write_sideband(1, x)
 
-        graph_walker = ProtocolGraphWalker(self)
-        objects_iter = self.backend.fetch_objects(
+        graph_walker = ProtocolGraphWalker(self, self.repo.object_store)
+        objects_iter = self.repo.fetch_objects(
           graph_walker.determine_wants, graph_walker, self.progress,
           get_tagged=self.get_tagged)
 
@@ -275,9 +298,9 @@ class ProtocolGraphWalker(object):
     call to set_ack_level() is required to set up the implementation, before any
     calls to next() or ack() are made.
     """
-    def __init__(self, handler):
+    def __init__(self, handler, object_store):
         self.handler = handler
-        self.store = handler.backend.object_store
+        self.store = object_store
         self.proto = handler.proto
         self.stateless_rpc = handler.stateless_rpc
         self.advertise_refs = handler.advertise_refs
@@ -557,6 +580,7 @@ class ReceivePackHandler(Handler):
     def __init__(self, backend, args, read, write,
                  stateless_rpc=False, advertise_refs=False):
         Handler.__init__(self, backend, read, write)
+        self.repo = backend.open_repository(args[0])
         self.stateless_rpc = stateless_rpc
         self.advertise_refs = advertise_refs
 
@@ -564,7 +588,7 @@ class ReceivePackHandler(Handler):
         return ("report-status", "delete-refs")
 
     def handle(self):
-        refs = self.backend.get_refs().items()
+        refs = self.repo.get_refs().items()
 
         if self.advertise_refs or not self.stateless_rpc:
             if refs:
@@ -598,8 +622,8 @@ class ReceivePackHandler(Handler):
             ref = self.proto.read_pkt_line()
 
         # backend can now deal with this refs and read a pack using self.read
-        status = self.backend.apply_pack(client_refs, self.proto.read,
-                                         self.has_capability('delete-refs'))
+        status = self.repo.apply_pack(client_refs, self.proto.read,
+            self.has_capability('delete-refs'))
 
         # when we have read all the pack from the client, send a status report
         # if the client asked for it

+ 12 - 7
dulwich/tests/test_server.py

@@ -26,12 +26,15 @@ from dulwich.errors import (
     GitProtocolError,
     )
 from dulwich.server import (
-    UploadPackHandler,
+    Backend,
+    DictBackend,
+    BackendRepo,
     Handler,
-    ProtocolGraphWalker,
-    SingleAckGraphWalkerImpl,
     MultiAckGraphWalkerImpl,
     MultiAckDetailedGraphWalkerImpl,
+    ProtocolGraphWalker,
+    SingleAckGraphWalkerImpl,
+    UploadPackHandler,
     )
 
 
@@ -76,7 +79,7 @@ class TestProto(object):
 class HandlerTestCase(TestCase):
 
     def setUp(self):
-        self._handler = Handler(None, None, None)
+        self._handler = Handler(Backend(), None, None)
         self._handler.capabilities = lambda: ('cap1', 'cap2', 'cap3')
         self._handler.required_capabilities = lambda: ('cap2',)
 
@@ -119,8 +122,9 @@ class HandlerTestCase(TestCase):
 class UploadPackHandlerTestCase(TestCase):
 
     def setUp(self):
-        self._handler = UploadPackHandler(None, ["/", "host=lolcathost"],
-                                          None, None)
+        self._backend = DictBackend({"/": BackendRepo()})
+        self._handler = UploadPackHandler(self._backend,
+                ["/", "host=lolcathost"], None, None)
         self._handler.proto = TestProto()
 
     def test_progress(self):
@@ -224,7 +228,8 @@ class ProtocolGraphWalkerTestCase(TestCase):
             }
 
         self._walker = ProtocolGraphWalker(
-            TestUploadPackHandler(self._objects, TestProto()))
+            TestUploadPackHandler(self._objects, TestProto()),
+            self._objects)
 
     def test_is_satisfied_no_haves(self):
         self.assertFalse(self._walker._is_satisfied([], ONE, 0))