Browse Source

Add porcelain for receive-pack and upload-pack.

Jelmer Vernooij 10 years ago
parent
commit
3df32af314
6 changed files with 104 additions and 11 deletions
  1. 4 0
      NEWS
  2. 2 2
      bin/dul-receive-pack
  3. 2 2
      bin/dul-upload-pack
  4. 16 2
      bin/dulwich
  5. 47 5
      dulwich/porcelain.py
  6. 33 0
      dulwich/tests/test_porcelain.py

+ 4 - 0
NEWS

@@ -1,5 +1,9 @@
 0.9.8	UNRELEASED
 
+ IMPROVEMENTS
+
+  * Add porcelain 'receive-pack' and 'upload-pack'. (Jelmer Vernooij)
+
 0.9.7	2014-06-08
 
  BUG FIXES

+ 2 - 2
bin/dul-receive-pack

@@ -17,7 +17,7 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
 
-from dulwich.server import serve_command, ReceivePackHandler
+from dulwich.porcelain import receive_pack
 import os
 import sys
 
@@ -25,4 +25,4 @@ if len(sys.argv) < 2:
     sys.stderr.write("usage: %s <git-dir>\n" % os.path.basename(sys.argv[0]))
     sys.exit(1)
 
-sys.exit(serve_command(ReceivePackHandler))
+sys.exit(receive_pack(sys.argv[1]))

+ 2 - 2
bin/dul-upload-pack

@@ -17,7 +17,7 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
 
-from dulwich.server import serve_command, UploadPackHandler
+from dulwich.porcelain import upload_pack
 import os
 import sys
 
@@ -25,4 +25,4 @@ if len(sys.argv) < 2:
     sys.stderr.write("usage: %s <git-dir>\n" % os.path.basename(sys.argv[0]))
     sys.exit(1)
 
-sys.exit(serve_command(UploadPackHandler))
+sys.exit(upload_pack(sys.argv[1]))

+ 16 - 2
bin/dulwich

@@ -259,8 +259,8 @@ def cmd_daemon(args):
     options, args = parser.parse_args(args)
 
     log_utils.default_logging_config()
-    if len(args) > 1:
-        gitdir = args[1]
+    if len(args) >= 1:
+        gitdir = args[0]
     else:
         gitdir = '.'
     from dulwich import porcelain
@@ -268,6 +268,18 @@ def cmd_daemon(args):
                      port=options.port)
 
 
+def cmd_receive_pack(args):
+    parser = optparse.OptionParser()
+    options, args = parser.parse_args(args)
+    porcelain.receive_pack(args[0])
+
+
+def cmd_upload_pack(args):
+    parser = optparse.OptionParser()
+    options, args = parser.parse_args(args)
+    porcelain.upload_pack(args[0])
+
+
 commands = {
     "add": cmd_add,
     "archive": cmd_archive,
@@ -283,6 +295,7 @@ commands = {
     "fetch": cmd_fetch,
     "init": cmd_init,
     "log": cmd_log,
+    "receive-pack": cmd_receive_pack,
     "reset": cmd_reset,
     "rev-list": cmd_rev_list,
     "rm": cmd_rm,
@@ -290,6 +303,7 @@ commands = {
     "symbolic-ref": cmd_symbolic_ref,
     "tag": cmd_tag,
     "update-server-info": cmd_update_server_info,
+    "upload-pack": cmd_upload_pack,
     }
 
 if len(sys.argv) < 2:

+ 47 - 5
dulwich/porcelain.py

@@ -31,9 +31,11 @@ Currently implemented:
  * pull
  * push
  * rm
+ * receive-pack
  * reset
  * rev-list
  * tag
+ * upload-pack
  * update-server-info
  * status
  * symbolic-ref
@@ -62,8 +64,16 @@ from dulwich.objects import (
     )
 from dulwich.objectspec import parse_object
 from dulwich.patch import write_tree_diff
+from dulwich.protocol import Protocol
 from dulwich.repo import (BaseRepo, Repo)
-from dulwich.server import update_server_info as server_update_server_info
+from dulwich.server import (
+    FileSystemBackend,
+    TCPGitServer,
+    ReceivePackHandler,
+    UploadPackHandler,
+    update_server_info as server_update_server_info,
+    )
+
 
 # Module level tuple definition for status output
 GitStatus = namedtuple('GitStatus', 'staged unstaged untracked')
@@ -549,10 +559,42 @@ def daemon(path=".", address=None, port=None):
     :param path: Path to the directory to serve.
     """
     # TODO(jelmer): Support git-daemon-export-ok and --export-all.
-    from dulwich.server import (
-        FileSystemBackend,
-        TCPGitServer,
-        )
     backend = FileSystemBackend(path)
     server = TCPGitServer(backend, address, port)
     server.serve_forever()
+
+
+def upload_pack(path=".", inf=sys.stdin, outf=sys.stdout):
+    """Upload a pack file after negotiating its contents using smart protocol.
+
+    :param path: Path to the repository
+    :param inf: Input stream to communicate with client
+    :param outf: Output stream to communicate with client
+    """
+    backend = FileSystemBackend()
+    def send_fn(data):
+        outf.write(data)
+        outf.flush()
+    proto = Protocol(inf.read, send_fn)
+    handler = UploadPackHandler(backend, [path], proto)
+    # FIXME: Catch exceptions and write a single-line summary to outf.
+    handler.handle()
+    return 0
+
+
+def receive_pack(path=".", inf=sys.stdin, outf=sys.stdout):
+    """Receive a pack file after negotiating its contents using smart protocol.
+
+    :param path: Path to the repository
+    :param inf: Input stream to communicate with client
+    :param outf: Output stream to communicate with client
+    """
+    backend = FileSystemBackend()
+    def send_fn(data):
+        outf.write(data)
+        outf.flush()
+    proto = Protocol(inf.read, send_fn)
+    handler = ReceivePackHandler(backend, [path], proto)
+    # FIXME: Catch exceptions and write a single-line summary to outf.
+    handler.handle()
+    return 0

+ 33 - 0
dulwich/tests/test_porcelain.py

@@ -597,3 +597,36 @@ class StatusTests(PorcelainTestCase):
 
 
 # TODO(jelmer): Add test for dulwich.porcelain.daemon
+
+
+class UploadPackTests(PorcelainTestCase):
+    """Tests for upload_pack."""
+
+    def test_upload_pack(self):
+        outf = BytesIO()
+        exitcode = porcelain.upload_pack(self.repo.path, BytesIO("0000"), outf)
+        outlines = outf.getvalue().splitlines()
+        self.assertEqual(["0000"], outlines)
+        self.assertEqual(0, exitcode)
+
+
+class ReceivePackTests(PorcelainTestCase):
+    """Tests for receive_pack."""
+
+    def test_receive_pack(self):
+        filename = 'foo'
+        with open(os.path.join(self.repo.path, filename), 'w') as f:
+            f.write('stuff')
+        porcelain.add(repo=self.repo.path, paths=filename)
+        self.repo.do_commit(message='test status',
+            author='', committer='', author_timestamp=1402354300,
+            commit_timestamp=1402354300, author_timezone=0, commit_timezone=0)
+        outf = BytesIO()
+        exitcode = porcelain.receive_pack(self.repo.path, BytesIO("0000"), outf)
+        outlines = outf.getvalue().splitlines()
+        self.assertEqual([
+            '005a9e65bdcf4a22cdd4f3700604a275cd2aaf146b23 HEAD\x00report-status '
+            'delete-refs side-band-64k',
+            '003f9e65bdcf4a22cdd4f3700604a275cd2aaf146b23 refs/heads/master',
+            '0000'], outlines)
+        self.assertEqual(0, exitcode)