Ryan Faulkner 11 роки тому
батько
коміт
0f25d996d3
3 змінених файлів з 85 додано та 0 видалено
  1. 4 0
      NEWS
  2. 37 0
      dulwich/porcelain.py
  3. 44 0
      dulwich/tests/test_porcelain.py

+ 4 - 0
NEWS

@@ -1,5 +1,9 @@
 0.9.6	UNRELEASED
 
+ IMPROVEMENTS
+
+ * Add porcelain 'push'. (Ryan Faulkner)
+
 0.9.5	2014-02-23
 
  IMPROVEMENTS

+ 37 - 0
dulwich/porcelain.py

@@ -22,6 +22,10 @@ import time
 
 from dulwich import index
 from dulwich.client import get_transport_and_path
+from dulwich.errors import (
+    SendPackError,
+    UpdateRefsError,
+    )
 from dulwich.objects import (
     Commit,
     Tag,
@@ -42,6 +46,7 @@ Currently implemented:
  * commit-tree
  * diff-tree
  * init
+ * push
  * remove
  * reset
  * rev-list
@@ -383,3 +388,35 @@ def reset(repo, mode, committish="HEAD"):
     indexfile = r.index_path()
     tree = r[committish].tree
     index.build_index_from_tree(r.path, indexfile, r.object_store, tree)
+
+
+def push(repo, remote_location, refs_path,
+         outstream=sys.stdout, errstream=sys.stderr):
+    """Remote push with dulwich via dulwich.client
+
+    :param repo : Path to repository
+    :param remote_location: Location of the remote
+    :param refs_path: relative path to the refs to push to remote
+    :param outstream: A stream file to write output
+    :param outstream: A stream file to write errors
+    """
+
+    # Open the repo
+    r = open_repo(repo)
+
+    # Get the client and path
+    client, path = get_transport_and_path(remote_location)
+
+    def update_refs(refs):
+        new_refs = r.get_refs()
+        refs[refs_path] = new_refs['HEAD']
+        del new_refs['HEAD']
+        return refs
+
+    try:
+        client.send_pack(path, update_refs,
+            r.object_store.generate_pack_contents, progress=errstream.write)
+        outstream.write("Push to %s successful.\n" % remote_location)
+    except (UpdateRefsError, SendPackError) as e:
+        outstream.write("Push to %s failed.\n" % remote_location)
+        errstream.write("Push to %s failed -> '%s'\n" % e.message)

+ 44 - 0
dulwich/tests/test_porcelain.py

@@ -373,3 +373,47 @@ class ResetTests(PorcelainTestCase):
                        self.repo['HEAD'].tree))
 
         self.assertEquals([], changes)
+
+
+class PushTests(PorcelainTestCase):
+
+    def test_simple(self):
+        """
+        Basic test of porcelain push where self.repo is the remote.  First
+        clone the remote, commit a file to the clone, then push the changes
+        back to the remote.
+        """
+        outstream = StringIO()
+        errstream = StringIO()
+
+        porcelain.commit(repo=self.repo.path, message='init',
+            author='', committer='')
+
+        # Setup target repo cloned from temp test repo
+        clone_path = tempfile.mkdtemp()
+        porcelain.clone(self.repo.path, target=clone_path, outstream=outstream)
+
+        # create a second file to be pushed back to origin
+        handle, fullpath = tempfile.mkstemp(dir=clone_path)
+        porcelain.add(repo=clone_path, paths=[os.path.basename(fullpath)])
+        porcelain.commit(repo=clone_path, message='push',
+            author='', committer='')
+
+        # Setup a non-checked out branch in the remote
+        refs_path = os.path.join('refs', 'heads', 'foo')
+        self.repo[refs_path] = self.repo['HEAD']
+
+        # Push to the remote
+        porcelain.push(clone_path, self.repo.path, refs_path, outstream=outstream,
+                errstream=errstream)
+
+        # Check that the target and source
+        r_clone = Repo(clone_path)
+
+        # Get the change in the target repo corresponding to the add
+        # this will be in the foo branch.
+        change = list(tree_changes(self.repo, self.repo['HEAD'].tree,
+                                   self.repo['refs/heads/foo'].tree))[0]
+
+        self.assertEquals(r_clone['HEAD'].id, self.repo[refs_path].id)
+        self.assertEquals(os.path.basename(fullpath), change.new.path)