Browse Source

Add basic server side implementation of 'git-upload-archive'.

Jelmer Vernooij 6 years ago
parent
commit
d0f921ed63
2 changed files with 38 additions and 4 deletions
  1. 3 0
      NEWS
  2. 35 4
      dulwich/server.py

+ 3 - 0
NEWS

@@ -6,6 +6,9 @@
  * Preserve port and username in parsed HTTP URLs.
    (Jelmer Vernooij)
 
+ * Add basic server side implementation of ``git-upload-archivw``.
+   (Jelmer Vernooij)
+
 0.19.7	2018-11-05
 
  CHANGES

+ 35 - 4
dulwich/server.py

@@ -46,6 +46,7 @@ import collections
 import os
 import socket
 import sys
+import time
 import zlib
 
 try:
@@ -53,6 +54,7 @@ try:
 except ImportError:
     import socketserver as SocketServer
 
+from dulwich.archive import tar_stream
 from dulwich.errors import (
     ApplyDeltaError,
     ChecksumMismatch,
@@ -1003,19 +1005,48 @@ class ReceivePackHandler(PackHandler):
 
 class UploadArchiveHandler(Handler):
 
-    def __init__(self, backend, proto, http_req=None):
+    def __init__(self, backend, args, proto, http_req=None):
         super(UploadArchiveHandler, self).__init__(backend, proto, http_req)
+        self.repo = backend.open_repository(args[0])
 
     def handle(self):
-        # TODO(jelmer)
-        raise NotImplementedError(self.handle)
+        def write(x):
+            return self.proto.write_sideband(SIDE_BAND_CHANNEL_DATA, x)
+        arguments = []
+        for pkt in self.proto.read_pkt_seq():
+            (key, value) = pkt.split(b' ', 1)
+            if key != b'argument':
+                raise GitProtocolError('unknown command %s' % key)
+            arguments.append(value.rstrip(b'\n'))
+        prefix = b''
+        format = 'tar'
+        i = 0
+        store = self.repo.object_store
+        while i < len(arguments):
+            argument = arguments[i]
+            if argument == b'--prefix':
+                i += 1
+                prefix = arguments[i]
+            elif argument == b'--format':
+                i += 1
+                format = arguments[i].decode('ascii')
+            else:
+                commit_sha = self.repo.refs[argument]
+                tree = store[store[commit_sha].tree]
+            i += 1
+        self.proto.write_pkt_line(b'ACK\n')
+        self.proto.write_pkt_line(None)
+        for chunk in tar_stream(
+                store, tree, mtime=time.time(), prefix=prefix, format=format):
+            write(chunk)
+        self.proto.write_pkt_line(None)
 
 
 # Default handler classes for git services.
 DEFAULT_HANDLERS = {
   b'git-upload-pack': UploadPackHandler,
   b'git-receive-pack': ReceivePackHandler,
-  # b'git-upload-archive': UploadArchiveHandler,
+  b'git-upload-archive': UploadArchiveHandler,
 }