Jelajahi Sumber

Smart protocol clients can now change refs even if they are not uploading new data.

Jelmer Vernooij 13 tahun lalu
induk
melakukan
ea94de72ff
3 mengubah file dengan 37 tambahan dan 14 penghapusan
  1. 3 0
      NEWS
  2. 10 8
      dulwich/client.py
  3. 24 6
      dulwich/tests/compat/test_client.py

+ 3 - 0
NEWS

@@ -27,6 +27,9 @@
 
   * Special case 'refs/stash' as a valid ref. (Jelmer Vernooij, #695577)
 
+  * Smart protocol clients can now change refs even if they are
+    not uploading new data. (Jelmer Vernooij, #855993)
+
 0.8.0	2011-08-07
 
  FEATURES

+ 10 - 8
dulwich/client.py

@@ -416,15 +416,16 @@ class TraditionalGitClient(GitClient):
         if 'report-status' not in server_capabilities:
             negotiated_capabilities.remove('report-status')
         new_refs = determine_wants(old_refs)
-        if not new_refs:
+        if new_refs is None:
             proto.write_pkt_line(None)
-            return {}
+            return old_refs
         (have, want) = self._handle_receive_pack_head(proto,
             negotiated_capabilities, old_refs, new_refs)
-        if not want:
+        if not want and old_refs == new_refs:
             return new_refs
         objects = generate_pack_contents(have, want)
-        entries, sha = write_pack_objects(proto.write_file(), objects)
+        if len(objects) > 0:
+            entries, sha = write_pack_objects(proto.write_file(), objects)
         self._handle_receive_pack_tail(proto, negotiated_capabilities,
             progress)
         return new_refs
@@ -650,18 +651,19 @@ class HttpGitClient(GitClient):
             "git-receive-pack", url)
         negotiated_capabilities = list(self._send_capabilities)
         new_refs = determine_wants(old_refs)
-        if not new_refs:
-            return {}
+        if new_refs is None:
+            return old_refs
         if self.dumb:
             raise NotImplementedError(self.fetch_pack)
         req_data = StringIO()
         req_proto = Protocol(None, req_data.write)
         (have, want) = self._handle_receive_pack_head(
             req_proto, negotiated_capabilities, old_refs, new_refs)
-        if not want:
+        if not want and old_refs == new_refs:
             return new_refs
         objects = generate_pack_contents(have, want)
-        entries, sha = write_pack_objects(req_proto.write_file(), objects)
+        if len(objects) > 0:
+            entries, sha = write_pack_objects(req_proto.write_file(), objects)
         resp = self._smart_request("git-receive-pack", url,
             data=req_data.getvalue())
         resp_proto = Protocol(resp.read, None)

+ 24 - 6
dulwich/tests/compat/test_client.py

@@ -108,11 +108,7 @@ class DulwichClientTestBase(object):
                     src.object_store.generate_pack_contents)
         self.assertDestEqualsSrc()
 
-    def disable_ff_and_make_dummy_commit(self):
-        # disable non-fast-forward pushes to the server
-        dest = repo.Repo(os.path.join(self.gitroot, 'dest'))
-        run_git_or_fail(['config', 'receive.denyNonFastForwards', 'true'],
-                        cwd=dest.path)
+    def make_dummy_commit(self, dest):
         b = objects.Blob.from_string('hi')
         dest.object_store.add_object(b)
         t = index.commit_tree(dest.object_store, [('hi', b.id, 0100644)])
@@ -123,7 +119,15 @@ class DulwichClientTestBase(object):
         c.message = 'hi'
         c.tree = t
         dest.object_store.add_object(c)
-        return dest, c.id
+        return c.id
+
+    def disable_ff_and_make_dummy_commit(self):
+        # disable non-fast-forward pushes to the server
+        dest = repo.Repo(os.path.join(self.gitroot, 'dest'))
+        run_git_or_fail(['config', 'receive.denyNonFastForwards', 'true'],
+                        cwd=dest.path)
+        commit_id = self.make_dummy_commit(dest)
+        return dest, commit_id
 
     def compute_send(self):
         srcpath = os.path.join(self.gitroot, 'server_new.export')
@@ -177,6 +181,20 @@ class DulwichClientTestBase(object):
         map(lambda r: dest.refs.set_if_equals(r[0], None, r[1]), refs.items())
         self.assertDestEqualsSrc()
 
+    def test_send_remove_branch(self):
+        dest = repo.Repo(os.path.join(self.gitroot, 'dest'))
+        dummy_commit = self.make_dummy_commit(dest)
+        dest.refs['refs/heads/master'] = dummy_commit
+        dest.refs['refs/heads/abranch'] = dummy_commit
+        sendrefs = dict(dest.refs)
+        sendrefs['refs/heads/abranch'] = "00" * 20
+        del sendrefs['HEAD']
+        gen_pack = lambda have, want: []
+        c = self._client()
+        self.assertEquals(dest.refs["refs/heads/abranch"], dummy_commit)
+        c.send_pack(self._build_path('/dest'), lambda _: sendrefs, gen_pack)
+        self.assertFalse("refs/heads/abranch" in dest.refs)
+
 
 class DulwichTCPClientTest(CompatTestCase, DulwichClientTestBase):