Support Gerrit2's ssh:// based upload

In Gerrit2 uploads are sent over "git push ssh://...", as this
is a more efficient transport and is easier to code from external
scripts and/or direct command line usage by an end-user.

Gerrit1's HTTP POST based format is assumed if the review server
does not have the /ssh_info URL available on it.

Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/project.py b/project.py
index 7743ca1..5d036c3 100644
--- a/project.py
+++ b/project.py
@@ -46,6 +46,8 @@
 def not_rev(r):
   return '^' + r
 
+def sq(r):
+  return "'" + r.replace("'", "'\''") + "'"
 
 hook_list = None
 def repo_hooks():
@@ -475,33 +477,58 @@
     if not dest_branch.startswith(R_HEADS):
       dest_branch = R_HEADS + dest_branch
 
-    base_list = []
-    for name, id in self._allrefs.iteritems():
-      if branch.remote.WritesTo(name):
-        base_list.append(not_rev(name))
-    if not base_list:
-      raise GitError('no base refs, cannot upload %s' % branch.name)
-
     if not branch.remote.projectname:
       branch.remote.projectname = self.name
       branch.remote.Save()
 
-    print >>sys.stderr, ''
-    _info("Uploading %s to %s:", branch.name, self.name)
-    try:
-      UploadBundle(project = self,
-                   server = branch.remote.review,
-                   email = self.UserEmail,
-                   dest_project = branch.remote.projectname,
-                   dest_branch = dest_branch,
-                   src_branch = R_HEADS + branch.name,
-                   bases = base_list,
-                   people = people,
-                   replace_changes = replace_changes)
-    except proto_client.ClientLoginError:
-      raise UploadError('Login failure')
-    except urllib2.HTTPError, e:
-      raise UploadError('HTTP error %d' % e.code)
+    if branch.remote.ReviewProtocol == 'http-post':
+      base_list = []
+      for name, id in self._allrefs.iteritems():
+        if branch.remote.WritesTo(name):
+          base_list.append(not_rev(name))
+      if not base_list:
+        raise GitError('no base refs, cannot upload %s' % branch.name)
+
+      print >>sys.stderr, ''
+      _info("Uploading %s to %s:", branch.name, self.name)
+      try:
+        UploadBundle(project = self,
+                     server = branch.remote.review,
+                     email = self.UserEmail,
+                     dest_project = branch.remote.projectname,
+                     dest_branch = dest_branch,
+                     src_branch = R_HEADS + branch.name,
+                     bases = base_list,
+                     people = people,
+                     replace_changes = replace_changes)
+      except proto_client.ClientLoginError:
+        raise UploadError('Login failure')
+      except urllib2.HTTPError, e:
+        raise UploadError('HTTP error %d' % e.code)
+
+    elif branch.remote.ReviewProtocol == 'ssh':
+      if dest_branch.startswith(R_HEADS):
+        dest_branch = dest_branch[len(R_HEADS):]
+
+      rp = ['gerrit receive-pack']
+      for e in people[0]:
+        rp.append('--reviewer=%s' % sq(e))
+      for e in people[1]:
+        rp.append('--cc=%s' % sq(e))
+
+      cmd = ['push']
+      cmd.append('--receive-pack=%s' % " ".join(rp))
+      cmd.append(branch.remote.SshReviewUrl(self.UserEmail))
+      cmd.append('%s:refs/for/%s' % (R_HEADS + branch.name, dest_branch))
+      if replace_changes:
+        for change_id,commit_id in replace_changes.iteritems():
+          cmd.append('%s:refs/changes/%s/new' % (commit_id, change_id))
+      if GitCommand(self, cmd, bare = True).Wait() != 0:
+        raise UploadError('Upload failed')
+
+    else:
+        raise UploadError('Unsupported protocol %s' \
+          % branch.remote.review)
 
     msg = "posted to %s for %s" % (branch.remote.review, dest_branch)
     self.bare_git.UpdateRef(R_PUB + branch.name,