Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """ | 5 """ |
| 6 Utilities for requesting information for a gerrit server via https. | 6 Utilities for requesting information for a gerrit server via https. |
| 7 | 7 |
| 8 https://gerrit-review.googlesource.com/Documentation/rest-api.html | 8 https://gerrit-review.googlesource.com/Documentation/rest-api.html |
| 9 """ | 9 """ |
| 10 | 10 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 else: | 58 else: |
| 59 raise RuntimeError( | 59 raise RuntimeError( |
| 60 "Don't know how to work with protocol '%s'" % protocol) | 60 "Don't know how to work with protocol '%s'" % protocol) |
| 61 | 61 |
| 62 | 62 |
| 63 def CreateHttpConn(host, path, reqtype='GET', headers=None, body=None): | 63 def CreateHttpConn(host, path, reqtype='GET', headers=None, body=None): |
| 64 """Opens an https connection to a gerrit service, and sends a request.""" | 64 """Opens an https connection to a gerrit service, and sends a request.""" |
| 65 headers = headers or {} | 65 headers = headers or {} |
| 66 bare_host = host.partition(':')[0] | 66 bare_host = host.partition(':')[0] |
| 67 auth = NETRC.authenticators(bare_host) | 67 auth = NETRC.authenticators(bare_host) |
| 68 | |
| 68 if auth: | 69 if auth: |
| 69 headers.setdefault('Authorization', 'Basic %s' % ( | 70 headers.setdefault('Authorization', 'Basic %s' % ( |
| 70 base64.b64encode('%s:%s' % (auth[0], auth[2])))) | 71 base64.b64encode('%s:%s' % (auth[0], auth[2])))) |
| 72 url = '/a/%s' % path | |
|
szager1
2013/10/31 18:15:45
It's always possible that the Authorization header
deymo
2013/10/31 20:42:12
Done.
| |
| 71 else: | 73 else: |
| 72 LOGGER.debug('No authorization found') | 74 LOGGER.debug('No authorization found') |
| 75 url = '/%s' % path | |
| 73 if body: | 76 if body: |
| 74 body = json.JSONEncoder().encode(body) | 77 body = json.JSONEncoder().encode(body) |
| 75 headers.setdefault('Content-Type', 'application/json') | 78 headers.setdefault('Content-Type', 'application/json') |
| 76 if LOGGER.isEnabledFor(logging.DEBUG): | 79 if LOGGER.isEnabledFor(logging.DEBUG): |
| 77 LOGGER.debug('%s %s://%s/a/%s' % (reqtype, GERRIT_PROTOCOL, host, path)) | 80 LOGGER.debug('%s %s://%s/a/%s' % (reqtype, GERRIT_PROTOCOL, host, path)) |
|
szager1
2013/10/31 18:15:45
Use the new 'url' variable.
deymo
2013/10/31 20:42:12
Done.
| |
| 78 for key, val in headers.iteritems(): | 81 for key, val in headers.iteritems(): |
| 79 if key == 'Authorization': | 82 if key == 'Authorization': |
| 80 val = 'HIDDEN' | 83 val = 'HIDDEN' |
| 81 LOGGER.debug('%s: %s' % (key, val)) | 84 LOGGER.debug('%s: %s' % (key, val)) |
| 82 if body: | 85 if body: |
| 83 LOGGER.debug(body) | 86 LOGGER.debug(body) |
| 84 conn = GetConnectionClass()(host) | 87 conn = GetConnectionClass()(host) |
| 85 conn.req_host = host | 88 conn.req_host = host |
| 86 conn.req_params = { | 89 conn.req_params = { |
| 87 'url': '/a/%s' % path, | 90 'url': url, |
| 88 'method': reqtype, | 91 'method': reqtype, |
| 89 'headers': headers, | 92 'headers': headers, |
| 90 'body': body, | 93 'body': body, |
| 91 } | 94 } |
| 92 conn.request(**conn.req_params) | 95 conn.request(**conn.req_params) |
| 93 return conn | 96 return conn |
| 94 | 97 |
| 95 | 98 |
| 96 def ReadHttpResponse(conn, expect_status=200, ignore_404=True): | 99 def ReadHttpResponse(conn, expect_status=200, ignore_404=True): |
| 97 """Reads an http response from a connection into a string buffer. | 100 """Reads an http response from a connection into a string buffer. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 if sortkey: | 176 if sortkey: |
| 174 path = '%s&N=%s' % (path, sortkey) | 177 path = '%s&N=%s' % (path, sortkey) |
| 175 if limit: | 178 if limit: |
| 176 path = '%s&n=%d' % (path, limit) | 179 path = '%s&n=%d' % (path, limit) |
| 177 if o_params: | 180 if o_params: |
| 178 path = '%s&%s' % (path, '&'.join(['o=%s' % p for p in o_params])) | 181 path = '%s&%s' % (path, '&'.join(['o=%s' % p for p in o_params])) |
| 179 # Don't ignore 404; a query should always return a list, even if it's empty. | 182 # Don't ignore 404; a query should always return a list, even if it's empty. |
| 180 return ReadHttpJsonResponse(CreateHttpConn(host, path), ignore_404=False) | 183 return ReadHttpJsonResponse(CreateHttpConn(host, path), ignore_404=False) |
| 181 | 184 |
| 182 | 185 |
| 186 def QueryAllChanges(host, param_dict, first_param=None, limit=500, | |
|
szager1
2013/10/31 18:15:45
This method name is not suggestive of what the cod
deymo
2013/10/31 20:42:12
The point of having the documentation here is that
| |
| 187 o_params=None, sortkey=None): | |
| 188 """ | |
| 189 Queries a gerrit-on-borg server for all the changes matching the query terms. | |
| 190 | |
| 191 A single query to gerrit-on-borg is limited on the number of results by the | |
| 192 limit parameter on the request (see QueryChanges) and the server maximum | |
| 193 limit. This function uses the "_more_changes" and "_sortkey" attributes on | |
| 194 the returned changes to iterate all of them making multiple queries to the | |
| 195 server, regardless the query limit. | |
| 196 | |
| 197 Args: | |
| 198 param_dict: A dictionary of search parameters, as documented here: | |
| 199 http://gerrit-documentation.googlecode.com/svn/Documentation/2.6/user-se arch.html | |
| 200 first_param: A change identifier. | |
| 201 limit: Maximum number of requested changes per query. | |
| 202 o_params: A list of additional output specifiers, as documented here: | |
| 203 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.ht ml#list-changes | |
| 204 sortkey: The value of the "_sortkey" attribute where starts from. None to | |
| 205 start from the first change. | |
| 206 | |
| 207 Returns: | |
| 208 A generator object to the list of returned changes, possibly unbound. | |
| 209 """ | |
| 210 more_changes = True | |
| 211 while more_changes: | |
| 212 page = QueryChanges(host, param_dict, first_param, limit, o_params, sortkey) | |
| 213 for cl in page: | |
| 214 yield cl | |
| 215 | |
| 216 more_changes = [cl for cl in page if '_more_changes' in cl] | |
|
szager1
2013/10/31 18:15:45
This logic is a bit obscure, since '_more_changes'
deymo
2013/10/31 20:42:12
I try to avoid the "while True:" loops with breaks
| |
| 217 sortkey = None | |
| 218 if more_changes: | |
| 219 sortkey = more_changes[0]['_sortkey'] | |
| 220 | |
| 221 | |
| 183 def MultiQueryChanges(host, param_dict, change_list, limit=None, o_params=None, | 222 def MultiQueryChanges(host, param_dict, change_list, limit=None, o_params=None, |
| 184 sortkey=None): | 223 sortkey=None): |
| 185 """Initiate a query composed of multiple sets of query parameters.""" | 224 """Initiate a query composed of multiple sets of query parameters.""" |
| 186 if not change_list: | 225 if not change_list: |
| 187 raise RuntimeError( | 226 raise RuntimeError( |
| 188 "MultiQueryChanges requires a list of change numbers/id's") | 227 "MultiQueryChanges requires a list of change numbers/id's") |
| 189 q = ['q=%s' % '+OR+'.join([urllib.quote(str(x)) for x in change_list])] | 228 q = ['q=%s' % '+OR+'.join([urllib.quote(str(x)) for x in change_list])] |
| 190 if param_dict: | 229 if param_dict: |
| 191 q.append(_QueryString(param_dict)) | 230 q.append(_QueryString(param_dict)) |
| 192 if limit: | 231 if limit: |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 username = review.get('email', jmsg.get('name', '')) | 424 username = review.get('email', jmsg.get('name', '')) |
| 386 raise GerritError(200, 'Unable to set %s label for user "%s"' | 425 raise GerritError(200, 'Unable to set %s label for user "%s"' |
| 387 ' on change %s.' % (label, username, change)) | 426 ' on change %s.' % (label, username, change)) |
| 388 jmsg = GetChangeCurrentRevision(host, change) | 427 jmsg = GetChangeCurrentRevision(host, change) |
| 389 if not jmsg: | 428 if not jmsg: |
| 390 raise GerritError( | 429 raise GerritError( |
| 391 200, 'Could not get review information for change "%s"' % change) | 430 200, 'Could not get review information for change "%s"' % change) |
| 392 elif jmsg[0]['current_revision'] != revision: | 431 elif jmsg[0]['current_revision'] != revision: |
| 393 raise GerritError(200, 'While resetting labels on change "%s", ' | 432 raise GerritError(200, 'While resetting labels on change "%s", ' |
| 394 'a new patchset was uploaded.' % change) | 433 'a new patchset was uploaded.' % change) |
| OLD | NEW |