blob: 32451408ba87982445d6bdb9982754d114d1deba [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
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
16import getpass
17import os
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070018import sys
19from tempfile import mkstemp
20
21from codereview.proto_client import HttpRpc, Proxy
22from codereview.review_pb2 import ReviewService_Stub
23from codereview.upload_bundle_pb2 import *
24from git_command import GitCommand
25from error import UploadError
26
27try:
28 import readline
29except ImportError:
30 pass
31
32MAX_SEGMENT_SIZE = 1020 * 1024
33
34def _GetRpcServer(email, server, save_cookies):
35 """Returns an RpcServer.
36
37 Returns:
38 A new RpcServer, on which RPC calls can be made.
39 """
40
41 def GetUserCredentials():
42 """Prompts the user for a username and password."""
43 e = email
44 if e is None:
45 e = raw_input("Email: ").strip()
46 password = getpass.getpass("Password for %s: " % e)
47 return (e, password)
48
49 # If this is the dev_appserver, use fake authentication.
50 lc_server = server.lower()
51 if lc_server == "localhost" or lc_server.startswith("localhost:"):
52 if email is None:
53 email = "test@example.com"
54 server = HttpRpc(
55 server,
56 lambda: (email, "password"),
57 extra_headers={"Cookie":
58 'dev_appserver_login="%s:False"' % email})
59 # Don't try to talk to ClientLogin.
60 server.authenticated = True
61 return server
62
63 if save_cookies:
64 cookie_file = ".gerrit_cookies"
65 else:
66 cookie_file = None
67
68 return HttpRpc(server, GetUserCredentials,
69 cookie_file=cookie_file)
70
71def UploadBundle(project,
72 server,
73 email,
74 dest_project,
75 dest_branch,
76 src_branch,
77 bases,
Shawn O. Pearcec99883f2008-11-11 17:12:43 -080078 replace_changes = None,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070079 save_cookies=True):
80
81 srv = _GetRpcServer(email, server, save_cookies)
82 review = Proxy(ReviewService_Stub(srv))
83 tmp_fd, tmp_bundle = mkstemp(".bundle", ".gpq")
84 os.close(tmp_fd)
85
86 srcid = project.bare_git.rev_parse(src_branch)
87 revlist = project._revlist(src_branch, *bases)
88
89 if srcid not in revlist:
90 # This can happen if src_branch is an annotated tag
91 #
92 revlist.append(srcid)
93 revlist_size = len(revlist) * 42
94
95 try:
96 cmd = ['bundle', 'create', tmp_bundle, src_branch]
97 cmd.extend(bases)
98 if GitCommand(project, cmd).Wait() != 0:
99 raise UploadError('cannot create bundle')
100 fd = open(tmp_bundle, "rb")
101
102 bundle_id = None
103 segment_id = 0
104 next_data = fd.read(MAX_SEGMENT_SIZE - revlist_size)
105
106 while True:
107 this_data = next_data
108 next_data = fd.read(MAX_SEGMENT_SIZE)
109 segment_id += 1
110
111 if bundle_id is None:
112 req = UploadBundleRequest()
113 req.dest_project = str(dest_project)
114 req.dest_branch = str(dest_branch)
115 for c in revlist:
116 req.contained_object.append(c)
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800117 for change_id,commit_id in replace_changes.iteritems():
118 r = req.replace.add()
119 r.change_id = change_id
120 r.object_id = commit_id
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700121 else:
122 req = UploadBundleContinue()
123 req.bundle_id = bundle_id
124 req.segment_id = segment_id
125
126 req.bundle_data = this_data
127 if len(next_data) > 0:
128 req.partial_upload = True
129 else:
130 req.partial_upload = False
131
132 if bundle_id is None:
133 rsp = review.UploadBundle(req)
134 else:
135 rsp = review.ContinueBundle(req)
136
137 if rsp.status_code == UploadBundleResponse.CONTINUE:
138 bundle_id = rsp.bundle_id
139 elif rsp.status_code == UploadBundleResponse.RECEIVED:
140 bundle_id = rsp.bundle_id
141 return bundle_id
142 else:
143 if rsp.status_code == UploadBundleResponse.UNKNOWN_PROJECT:
144 reason = 'unknown project "%s"' % dest_project
145 elif rsp.status_code == UploadBundleResponse.UNKNOWN_BRANCH:
146 reason = 'unknown branch "%s"' % dest_branch
147 elif rsp.status_code == UploadBundleResponse.UNKNOWN_BUNDLE:
148 reason = 'unknown bundle'
149 elif rsp.status_code == UploadBundleResponse.NOT_BUNDLE_OWNER:
150 reason = 'not bundle owner'
151 elif rsp.status_code == UploadBundleResponse.BUNDLE_CLOSED:
152 reason = 'bundle closed'
153 elif rsp.status_code == UploadBundleResponse.UNAUTHORIZED_USER:
154 reason = ('Unauthorized user. Visit http://%s/hello to sign up.'
155 % server)
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800156 elif rsp.status_code == UploadBundleResponse.UNKNOWN_CHANGE:
157 reason = 'invalid change id'
158 elif rsp.status_code == UploadBundleResponse.CHANGE_CLOSED:
159 reason = 'one or more changes are closed'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700160 else:
161 reason = 'unknown error ' + str(rsp.status_code)
162 raise UploadError(reason)
163 finally:
164 os.unlink(tmp_bundle)