Support opening git repositories by path.
authorJelmer Vernooij <jelmer@samba.org>
Fri, 2 Apr 2010 01:21:35 +0000 (03:21 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Fri, 2 Apr 2010 01:21:35 +0000 (03:21 +0200)
bin/dul-daemon
bin/dul-web
dulwich/server.py
dulwich/tests/test_server.py

index 4f340051c46c572bd959fd3a14f64e532a26e028..1833bbce5d7c42a2d016fbee2cd3c4ce3a8229d5 100755 (executable)
 
 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()
index 018fbb0efa852fcf8efcf384b303ba56d023df61..c2ad19d5f9740828d85f4aacff0462fb7d099b32 100644 (file)
@@ -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)
index 1db0fb34602aa1bd7de1b1e634332af3a16933c3..c44cc010597020582ab460570eec08226eaeaff9 100644 (file)
@@ -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
index 95bdf70939b215a6d9232e362e6d8c08e65bdb99..ce56b14bc30a2dd247310c6a80e6ff31acf47d04 100644 (file)
@@ -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))