gerrit_upload.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #
  2. # Copyright (C) 2008 The Android Open Source Project
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import getpass
  16. import os
  17. import sys
  18. from tempfile import mkstemp
  19. from codereview.proto_client import HttpRpc, Proxy
  20. from codereview.review_pb2 import ReviewService_Stub
  21. from codereview.upload_bundle_pb2 import *
  22. from git_command import GitCommand
  23. from error import UploadError
  24. try:
  25. import readline
  26. except ImportError:
  27. pass
  28. MAX_SEGMENT_SIZE = 1020 * 1024
  29. def _GetRpcServer(email, server, save_cookies):
  30. """Returns an RpcServer.
  31. Returns:
  32. A new RpcServer, on which RPC calls can be made.
  33. """
  34. def GetUserCredentials():
  35. """Prompts the user for a username and password."""
  36. e = email
  37. if e is None:
  38. e = raw_input("Email: ").strip()
  39. password = getpass.getpass("Password for %s: " % e)
  40. return (e, password)
  41. # If this is the dev_appserver, use fake authentication.
  42. lc_server = server.lower()
  43. if lc_server == "localhost" or lc_server.startswith("localhost:"):
  44. if email is None:
  45. email = "test@example.com"
  46. server = HttpRpc(
  47. server,
  48. lambda: (email, "password"),
  49. extra_headers={"Cookie":
  50. 'dev_appserver_login="%s:False"' % email})
  51. # Don't try to talk to ClientLogin.
  52. server.authenticated = True
  53. return server
  54. if save_cookies:
  55. cookie_file = ".gerrit_cookies"
  56. else:
  57. cookie_file = None
  58. return HttpRpc(server, GetUserCredentials,
  59. cookie_file=cookie_file)
  60. def UploadBundle(project,
  61. server,
  62. email,
  63. dest_project,
  64. dest_branch,
  65. src_branch,
  66. bases,
  67. people,
  68. replace_changes = None,
  69. save_cookies=True):
  70. srv = _GetRpcServer(email, server, save_cookies)
  71. review = Proxy(ReviewService_Stub(srv))
  72. tmp_fd, tmp_bundle = mkstemp(".bundle", ".gpq")
  73. os.close(tmp_fd)
  74. srcid = project.bare_git.rev_parse(src_branch)
  75. revlist = project._revlist(src_branch, *bases)
  76. if srcid not in revlist:
  77. # This can happen if src_branch is an annotated tag
  78. #
  79. revlist.append(srcid)
  80. revlist_size = len(revlist) * 42
  81. try:
  82. cmd = ['bundle', 'create', tmp_bundle, src_branch]
  83. cmd.extend(bases)
  84. if GitCommand(project, cmd).Wait() != 0:
  85. raise UploadError('cannot create bundle')
  86. fd = open(tmp_bundle, "rb")
  87. bundle_id = None
  88. segment_id = 0
  89. next_data = fd.read(MAX_SEGMENT_SIZE - revlist_size)
  90. while True:
  91. this_data = next_data
  92. next_data = fd.read(MAX_SEGMENT_SIZE)
  93. segment_id += 1
  94. if bundle_id is None:
  95. req = UploadBundleRequest()
  96. req.dest_project = str(dest_project)
  97. req.dest_branch = str(dest_branch)
  98. for e in people[0]:
  99. req.reviewers.append(e)
  100. for e in people[1]:
  101. req.cc.append(e)
  102. for c in revlist:
  103. req.contained_object.append(c)
  104. if replace_changes:
  105. for change_id,commit_id in replace_changes.iteritems():
  106. r = req.replace.add()
  107. r.change_id = change_id
  108. r.object_id = commit_id
  109. else:
  110. req = UploadBundleContinue()
  111. req.bundle_id = bundle_id
  112. req.segment_id = segment_id
  113. req.bundle_data = this_data
  114. if len(next_data) > 0:
  115. req.partial_upload = True
  116. else:
  117. req.partial_upload = False
  118. if bundle_id is None:
  119. rsp = review.UploadBundle(req)
  120. else:
  121. rsp = review.ContinueBundle(req)
  122. if rsp.status_code == UploadBundleResponse.CONTINUE:
  123. bundle_id = rsp.bundle_id
  124. elif rsp.status_code == UploadBundleResponse.RECEIVED:
  125. bundle_id = rsp.bundle_id
  126. return bundle_id
  127. else:
  128. if rsp.status_code == UploadBundleResponse.UNKNOWN_PROJECT:
  129. reason = 'unknown project "%s"' % dest_project
  130. elif rsp.status_code == UploadBundleResponse.UNKNOWN_BRANCH:
  131. reason = 'unknown branch "%s"' % dest_branch
  132. elif rsp.status_code == UploadBundleResponse.UNKNOWN_BUNDLE:
  133. reason = 'unknown bundle'
  134. elif rsp.status_code == UploadBundleResponse.NOT_BUNDLE_OWNER:
  135. reason = 'not bundle owner'
  136. elif rsp.status_code == UploadBundleResponse.BUNDLE_CLOSED:
  137. reason = 'bundle closed'
  138. elif rsp.status_code == UploadBundleResponse.UNAUTHORIZED_USER:
  139. reason = ('Unauthorized user. Visit http://%s/hello to sign up.'
  140. % server)
  141. elif rsp.status_code == UploadBundleResponse.UNKNOWN_CHANGE:
  142. reason = 'invalid change id'
  143. elif rsp.status_code == UploadBundleResponse.CHANGE_CLOSED:
  144. reason = 'one or more changes are closed'
  145. elif rsp.status_code == UploadBundleResponse.UNKNOWN_EMAIL:
  146. emails = [x for x in rsp.invalid_reviewers] + [
  147. x for x in rsp.invalid_cc]
  148. reason = 'invalid email addresses: %s' % ", ".join(emails)
  149. else:
  150. reason = 'unknown error ' + str(rsp.status_code)
  151. raise UploadError(reason)
  152. finally:
  153. os.unlink(tmp_bundle)