OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # coding: utf-8 |
2 # | 3 # |
3 # Copyright 2007 Google Inc. | 4 # Copyright 2007 Google Inc. |
4 # | 5 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # you may not use this file except in compliance with the License. | 7 # you may not use this file except in compliance with the License. |
7 # You may obtain a copy of the License at | 8 # You may obtain a copy of the License at |
8 # | 9 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 11 # |
11 # Unless required by applicable law or agreed to in writing, software | 12 # Unless required by applicable law or agreed to in writing, software |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 """Returns an OpenerDirector for making HTTP requests. | 209 """Returns an OpenerDirector for making HTTP requests. |
209 | 210 |
210 Returns: | 211 Returns: |
211 A urllib2.OpenerDirector object. | 212 A urllib2.OpenerDirector object. |
212 """ | 213 """ |
213 raise NotImplementedError() | 214 raise NotImplementedError() |
214 | 215 |
215 def _CreateRequest(self, url, data=None): | 216 def _CreateRequest(self, url, data=None): |
216 """Creates a new urllib request.""" | 217 """Creates a new urllib request.""" |
217 logging.debug("Creating request for: '%s' with payload:\n%s", url, data) | 218 logging.debug("Creating request for: '%s' with payload:\n%s", url, data) |
218 req = urllib2.Request(url, data=data) | 219 req = urllib2.Request(url, data=data, headers={"Accept": "text/plain"}) |
219 if self.host_override: | 220 if self.host_override: |
220 req.add_header("Host", self.host_override) | 221 req.add_header("Host", self.host_override) |
221 for key, value in self.extra_headers.iteritems(): | 222 for key, value in self.extra_headers.iteritems(): |
222 req.add_header(key, value) | 223 req.add_header(key, value) |
223 return req | 224 return req |
224 | 225 |
225 def _GetAuthToken(self, email, password): | 226 def _GetAuthToken(self, email, password): |
226 """Uses ClientLogin to authenticate the user, returning an auth token. | 227 """Uses ClientLogin to authenticate the user, returning an auth token. |
227 | 228 |
228 Args: | 229 Args: |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 try: | 393 try: |
393 f = self.opener.open(req) | 394 f = self.opener.open(req) |
394 response = f.read() | 395 response = f.read() |
395 f.close() | 396 f.close() |
396 return response | 397 return response |
397 except urllib2.HTTPError, e: | 398 except urllib2.HTTPError, e: |
398 if tries > 3: | 399 if tries > 3: |
399 raise | 400 raise |
400 elif e.code == 401 or e.code == 302: | 401 elif e.code == 401 or e.code == 302: |
401 self._Authenticate() | 402 self._Authenticate() |
402 ## elif e.code >= 500 and e.code < 600: | |
403 ## # Server Error - try again. | |
404 ## continue | |
405 elif e.code == 301: | 403 elif e.code == 301: |
406 # Handle permanent redirect manually. | 404 # Handle permanent redirect manually. |
407 url = e.info()["location"] | 405 url = e.info()["location"] |
408 url_loc = urlparse.urlparse(url) | 406 url_loc = urlparse.urlparse(url) |
409 self.host = '%s://%s' % (url_loc[0], url_loc[1]) | 407 self.host = '%s://%s' % (url_loc[0], url_loc[1]) |
| 408 elif e.code >= 500: |
| 409 ErrorExit(e.read()) |
410 else: | 410 else: |
411 raise | 411 raise |
412 finally: | 412 finally: |
413 socket.setdefaulttimeout(old_timeout) | 413 socket.setdefaulttimeout(old_timeout) |
414 | 414 |
415 | 415 |
416 class HttpRpcServer(AbstractRpcServer): | 416 class HttpRpcServer(AbstractRpcServer): |
417 """Provides a simplified RPC-style interface for HTTP requests.""" | 417 """Provides a simplified RPC-style interface for HTTP requests.""" |
418 | 418 |
419 def _Authenticate(self): | 419 def _Authenticate(self): |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 dest="save_cookies", default=True, | 525 dest="save_cookies", default=True, |
526 help="Do not save authentication cookies to local disk.") | 526 help="Do not save authentication cookies to local disk.") |
527 group.add_option("--account_type", action="store", dest="account_type", | 527 group.add_option("--account_type", action="store", dest="account_type", |
528 metavar="TYPE", default=AUTH_ACCOUNT_TYPE, | 528 metavar="TYPE", default=AUTH_ACCOUNT_TYPE, |
529 choices=["GOOGLE", "HOSTED"], | 529 choices=["GOOGLE", "HOSTED"], |
530 help=("Override the default account type " | 530 help=("Override the default account type " |
531 "(defaults to '%default', " | 531 "(defaults to '%default', " |
532 "valid choices are 'GOOGLE' and 'HOSTED').")) | 532 "valid choices are 'GOOGLE' and 'HOSTED').")) |
533 # Issue | 533 # Issue |
534 group = parser.add_option_group("Issue options") | 534 group = parser.add_option_group("Issue options") |
535 group.add_option("-d", "--description", action="store", dest="description", | 535 group.add_option("-t", "--title", action="store", dest="title", |
536 metavar="DESCRIPTION", default=None, | 536 help="New issue subject or new patch set title") |
537 help="Optional description when creating an issue.") | 537 group.add_option("-m", "--message", action="store", dest="message", |
538 group.add_option("-f", "--description_file", action="store", | |
539 dest="description_file", metavar="DESCRIPTION_FILE", | |
540 default=None, | 538 default=None, |
541 help="Optional path of a file that contains " | 539 help="New issue description or new patch set message") |
542 "the description when creating an issue.") | 540 group.add_option("-F", "--file", action="store", dest="file", |
| 541 default=None, help="Read the message above from file.") |
543 group.add_option("-r", "--reviewers", action="store", dest="reviewers", | 542 group.add_option("-r", "--reviewers", action="store", dest="reviewers", |
544 metavar="REVIEWERS", default=None, | 543 metavar="REVIEWERS", default=None, |
545 help="Add reviewers (comma separated email addresses).") | 544 help="Add reviewers (comma separated email addresses).") |
546 group.add_option("--cc", action="store", dest="cc", | 545 group.add_option("--cc", action="store", dest="cc", |
547 metavar="CC", default=None, | 546 metavar="CC", default=None, |
548 help="Add CC (comma separated email addresses).") | 547 help="Add CC (comma separated email addresses).") |
549 group.add_option("--private", action="store_true", dest="private", | 548 group.add_option("--private", action="store_true", dest="private", |
550 default=False, | 549 default=False, |
551 help="Make the issue restricted to reviewers and those CCed") | 550 help="Make the issue restricted to reviewers and those CCed") |
552 # Upload options | 551 # Upload options |
553 group = parser.add_option_group("Patch options") | 552 group = parser.add_option_group("Patch options") |
554 group.add_option("-m", "--message", action="store", dest="message", | |
555 metavar="MESSAGE", default=None, | |
556 help="A message to identify the patch. " | |
557 "Will prompt if omitted.") | |
558 group.add_option("-i", "--issue", type="int", action="store", | 553 group.add_option("-i", "--issue", type="int", action="store", |
559 metavar="ISSUE", default=None, | 554 metavar="ISSUE", default=None, |
560 help="Issue number to which to add. Defaults to new issue.") | 555 help="Issue number to which to add. Defaults to new issue.") |
561 group.add_option("--base_url", action="store", dest="base_url", default=None, | 556 group.add_option("--base_url", action="store", dest="base_url", default=None, |
562 help="Base URL path for files (listed as \"Base URL\" when " | 557 help="Base URL path for files (listed as \"Base URL\" when " |
563 "viewing issue). If omitted, will be guessed automatically " | 558 "viewing issue). If omitted, will be guessed automatically " |
564 "for SVN repos and left blank for others.") | 559 "for SVN repos and left blank for others.") |
565 group.add_option("--download_base", action="store_true", | 560 group.add_option("--download_base", action="store_true", |
566 dest="download_base", default=False, | 561 dest="download_base", default=False, |
567 help="Base files will be downloaded by the server " | 562 help="Base files will be downloaded by the server " |
(...skipping 889 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1457 | 1452 |
1458 def GetGUID(self): | 1453 def GetGUID(self): |
1459 # See chapter "Uniquely identifying a repository" | 1454 # See chapter "Uniquely identifying a repository" |
1460 # http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html | 1455 # http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html |
1461 info = RunShell("hg log -r0 --template {node}".split()) | 1456 info = RunShell("hg log -r0 --template {node}".split()) |
1462 return info.strip() | 1457 return info.strip() |
1463 | 1458 |
1464 def _GetRelPath(self, filename): | 1459 def _GetRelPath(self, filename): |
1465 """Get relative path of a file according to the current directory, | 1460 """Get relative path of a file according to the current directory, |
1466 given its logical path in the repo.""" | 1461 given its logical path in the repo.""" |
1467 assert filename.startswith(self.subdir), (filename, self.subdir) | 1462 absname = os.path.join(self.repo_dir, filename) |
1468 return filename[len(self.subdir):].lstrip(r"\/") | 1463 return os.path.relpath(absname) |
1469 | 1464 |
1470 def GenerateDiff(self, extra_args): | 1465 def GenerateDiff(self, extra_args): |
1471 cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args | 1466 cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args |
1472 data = RunShell(cmd, silent_ok=True) | 1467 data = RunShell(cmd, silent_ok=True) |
1473 svndiff = [] | 1468 svndiff = [] |
1474 filecount = 0 | 1469 filecount = 0 |
1475 for line in data.splitlines(): | 1470 for line in data.splitlines(): |
1476 m = re.match("diff --git a/(\S+) b/(\S+)", line) | 1471 m = re.match("diff --git a/(\S+) b/(\S+)", line) |
1477 if m: | 1472 if m: |
1478 # Modify line to make it look like as it comes from svn diff. | 1473 # Modify line to make it look like as it comes from svn diff. |
(...skipping 18 matching lines...) Expand all Loading... |
1497 status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], | 1492 status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], |
1498 silent_ok=True) | 1493 silent_ok=True) |
1499 unknown_files = [] | 1494 unknown_files = [] |
1500 for line in status.splitlines(): | 1495 for line in status.splitlines(): |
1501 st, fn = line.split(" ", 1) | 1496 st, fn = line.split(" ", 1) |
1502 if st == "?": | 1497 if st == "?": |
1503 unknown_files.append(fn) | 1498 unknown_files.append(fn) |
1504 return unknown_files | 1499 return unknown_files |
1505 | 1500 |
1506 def GetBaseFile(self, filename): | 1501 def GetBaseFile(self, filename): |
1507 # "hg status" and "hg cat" both take a path relative to the current subdir | 1502 # "hg status" and "hg cat" both take a path relative to the current subdir, |
1508 # rather than to the repo root, but "hg diff" has given us the full path | 1503 # but "hg diff" has given us the path relative to the repo root. |
1509 # to the repo root. | |
1510 base_content = "" | 1504 base_content = "" |
1511 new_content = None | 1505 new_content = None |
1512 is_binary = False | 1506 is_binary = False |
1513 oldrelpath = relpath = self._GetRelPath(filename) | 1507 oldrelpath = relpath = self._GetRelPath(filename) |
1514 # "hg status -C" returns two lines for moved/copied files, one otherwise | 1508 # "hg status -C" returns two lines for moved/copied files, one otherwise |
1515 out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) | 1509 out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) |
1516 out = out.splitlines() | 1510 out = out.splitlines() |
1517 # HACK: strip error message about missing file/directory if it isn't in | 1511 # HACK: strip error message about missing file/directory if it isn't in |
1518 # the working copy | 1512 # the working copy |
1519 if out[0].startswith('%s: ' % relpath): | 1513 if out[0].startswith('%s: ' % relpath): |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1568 ErrorExit("A changelist id is required") | 1562 ErrorExit("A changelist id is required") |
1569 if (options.revision): | 1563 if (options.revision): |
1570 ErrorExit("--rev is not supported for perforce") | 1564 ErrorExit("--rev is not supported for perforce") |
1571 | 1565 |
1572 self.p4_port = options.p4_port | 1566 self.p4_port = options.p4_port |
1573 self.p4_client = options.p4_client | 1567 self.p4_client = options.p4_client |
1574 self.p4_user = options.p4_user | 1568 self.p4_user = options.p4_user |
1575 | 1569 |
1576 ConfirmLogin() | 1570 ConfirmLogin() |
1577 | 1571 |
1578 if not options.message: | 1572 if not options.title: |
1579 description = self.RunPerforceCommand(["describe", self.p4_changelist], | 1573 description = self.RunPerforceCommand(["describe", self.p4_changelist], |
1580 marshal_output=True) | 1574 marshal_output=True) |
1581 if description and "desc" in description: | 1575 if description and "desc" in description: |
1582 # Rietveld doesn't support multi-line descriptions | 1576 # Rietveld doesn't support multi-line descriptions |
1583 raw_message = description["desc"].strip() | 1577 raw_title = description["desc"].strip() |
1584 lines = raw_message.splitlines() | 1578 lines = raw_title.splitlines() |
1585 if len(lines): | 1579 if len(lines): |
1586 options.message = lines[0] | 1580 options.title = lines[0] |
1587 | 1581 |
1588 def GetGUID(self): | 1582 def GetGUID(self): |
1589 """For now we don't know how to get repository ID for Perforce""" | 1583 """For now we don't know how to get repository ID for Perforce""" |
1590 return | 1584 return |
1591 | 1585 |
1592 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False, | 1586 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False, |
1593 universal_newlines=True): | 1587 universal_newlines=True): |
1594 args = ["p4"] | 1588 args = ["p4"] |
1595 if marshal_output: | 1589 if marshal_output: |
1596 # -G makes perforce format its output as marshalled python objects | 1590 # -G makes perforce format its output as marshalled python objects |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1967 if errcode != errno.ENOENT: # command not found code | 1961 if errcode != errno.ENOENT: # command not found code |
1968 raise | 1962 raise |
1969 | 1963 |
1970 # Mercurial has a command to get the base directory of a repository | 1964 # Mercurial has a command to get the base directory of a repository |
1971 # Try running it, but don't die if we don't have hg installed. | 1965 # Try running it, but don't die if we don't have hg installed. |
1972 # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. | 1966 # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. |
1973 res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"]) | 1967 res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"]) |
1974 if res != None: | 1968 if res != None: |
1975 return res | 1969 return res |
1976 | 1970 |
1977 # Subversion has a .svn in all working directories. | 1971 # Subversion from 1.7 has a single centralized .svn folder |
1978 if os.path.isdir('.svn'): | 1972 # ( see http://subversion.apache.org/docs/release-notes/1.7.html#wc-ng ) |
1979 logging.info("Guessed VCS = Subversion") | 1973 # That's why we use 'svn info' instead of checking for .svn dir |
1980 return (VCS_SUBVERSION, None) | 1974 res = RunDetectCommand(VCS_SUBVERSION, ["svn", "info"]) |
| 1975 if res != None: |
| 1976 return res |
1981 | 1977 |
1982 # Git has a command to test if you're in a git tree. | 1978 # Git has a command to test if you're in a git tree. |
1983 # Try running it, but don't die if we don't have git installed. | 1979 # Try running it, but don't die if we don't have git installed. |
1984 res = RunDetectCommand(VCS_GIT, ["git", "rev-parse", | 1980 res = RunDetectCommand(VCS_GIT, ["git", "rev-parse", |
1985 "--is-inside-work-tree"]) | 1981 "--is-inside-work-tree"]) |
1986 if res != None: | 1982 if res != None: |
1987 return res | 1983 return res |
1988 | 1984 |
1989 # detect CVS repos use `cvs status && $? == 0` rules | 1985 # detect CVS repos use `cvs status && $? == 0` rules |
1990 res = RunDetectCommand(VCS_CVS, ["cvs", "status"]) | 1986 res = RunDetectCommand(VCS_CVS, ["cvs", "status"]) |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2212 if data is None: | 2208 if data is None: |
2213 data = vcs.GenerateDiff(args) | 2209 data = vcs.GenerateDiff(args) |
2214 data = vcs.PostProcessDiff(data) | 2210 data = vcs.PostProcessDiff(data) |
2215 if options.print_diffs: | 2211 if options.print_diffs: |
2216 print "Rietveld diff start:*****" | 2212 print "Rietveld diff start:*****" |
2217 print data | 2213 print data |
2218 print "Rietveld diff end:*****" | 2214 print "Rietveld diff end:*****" |
2219 files = vcs.GetBaseFiles(data) | 2215 files = vcs.GetBaseFiles(data) |
2220 if verbosity >= 1: | 2216 if verbosity >= 1: |
2221 print "Upload server:", options.server, "(change with -s/--server)" | 2217 print "Upload server:", options.server, "(change with -s/--server)" |
2222 if options.issue: | |
2223 prompt = "Message describing this patch set: " | |
2224 else: | |
2225 prompt = "New issue subject: " | |
2226 message = options.message or raw_input(prompt).strip() | |
2227 if not message: | |
2228 ErrorExit("A non-empty message is required") | |
2229 rpc_server = GetRpcServer(options.server, | 2218 rpc_server = GetRpcServer(options.server, |
2230 options.email, | 2219 options.email, |
2231 options.host, | 2220 options.host, |
2232 options.save_cookies, | 2221 options.save_cookies, |
2233 options.account_type) | 2222 options.account_type) |
2234 form_fields = [("subject", message)] | 2223 form_fields = [] |
2235 | 2224 |
2236 repo_guid = vcs.GetGUID() | 2225 repo_guid = vcs.GetGUID() |
2237 if repo_guid: | 2226 if repo_guid: |
2238 form_fields.append(("repo_guid", repo_guid)) | 2227 form_fields.append(("repo_guid", repo_guid)) |
2239 if base: | 2228 if base: |
2240 b = urlparse.urlparse(base) | 2229 b = urlparse.urlparse(base) |
2241 username, netloc = urllib.splituser(b.netloc) | 2230 username, netloc = urllib.splituser(b.netloc) |
2242 if username: | 2231 if username: |
2243 logging.info("Removed username from base URL") | 2232 logging.info("Removed username from base URL") |
2244 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, | 2233 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, |
2245 b.query, b.fragment)) | 2234 b.query, b.fragment)) |
2246 form_fields.append(("base", base)) | 2235 form_fields.append(("base", base)) |
2247 if options.issue: | 2236 if options.issue: |
2248 form_fields.append(("issue", str(options.issue))) | 2237 form_fields.append(("issue", str(options.issue))) |
2249 if options.email: | 2238 if options.email: |
2250 form_fields.append(("user", options.email)) | 2239 form_fields.append(("user", options.email)) |
2251 if options.reviewers: | 2240 if options.reviewers: |
2252 for reviewer in options.reviewers.split(','): | 2241 for reviewer in options.reviewers.split(','): |
2253 CheckReviewer(reviewer) | 2242 CheckReviewer(reviewer) |
2254 form_fields.append(("reviewers", options.reviewers)) | 2243 form_fields.append(("reviewers", options.reviewers)) |
2255 if options.cc: | 2244 if options.cc: |
2256 for cc in options.cc.split(','): | 2245 for cc in options.cc.split(','): |
2257 CheckReviewer(cc) | 2246 CheckReviewer(cc) |
2258 form_fields.append(("cc", options.cc)) | 2247 form_fields.append(("cc", options.cc)) |
2259 description = options.description | 2248 |
2260 if options.description_file: | 2249 # Process --message, --title and --file. |
2261 if options.description: | 2250 message = options.message or "" |
2262 ErrorExit("Can't specify description and description_file") | 2251 title = options.title or "" |
2263 file = open(options.description_file, 'r') | 2252 if options.file: |
2264 description = file.read() | 2253 if options.message: |
| 2254 ErrorExit("Can't specify both message and message file options") |
| 2255 file = open(options.file, 'r') |
| 2256 message = file.read() |
2265 file.close() | 2257 file.close() |
2266 if description: | 2258 if options.issue: |
2267 form_fields.append(("description", description)) | 2259 prompt = "Title describing this patch set: " |
| 2260 else: |
| 2261 prompt = "New issue subject: " |
| 2262 title = ( |
| 2263 title or message.split('\n', 1)[0].strip() or raw_input(prompt)).strip() |
| 2264 if not title: |
| 2265 ErrorExit("A non-empty title is required") |
| 2266 if len(title) > 100: |
| 2267 title = title[:99] + '…' |
| 2268 if title and not options.issue: |
| 2269 message = message or title |
| 2270 |
| 2271 form_fields.append(("subject", title)) |
| 2272 if message: |
| 2273 if not options.issue: |
| 2274 form_fields.append(("description", message)) |
| 2275 else: |
| 2276 # TODO: [ ] Use /<issue>/publish to add a comment. |
| 2277 pass |
| 2278 |
2268 # Send a hash of all the base file so the server can determine if a copy | 2279 # Send a hash of all the base file so the server can determine if a copy |
2269 # already exists in an earlier patchset. | 2280 # already exists in an earlier patchset. |
2270 base_hashes = "" | 2281 base_hashes = "" |
2271 for file, info in files.iteritems(): | 2282 for file, info in files.iteritems(): |
2272 if not info[0] is None: | 2283 if not info[0] is None: |
2273 checksum = md5(info[0]).hexdigest() | 2284 checksum = md5(info[0]).hexdigest() |
2274 if base_hashes: | 2285 if base_hashes: |
2275 base_hashes += "|" | 2286 base_hashes += "|" |
2276 base_hashes += checksum + ":" + file | 2287 base_hashes += checksum + ":" + file |
2277 form_fields.append(("base_hashes", base_hashes)) | 2288 form_fields.append(("base_hashes", base_hashes)) |
2278 if options.private: | 2289 if options.private: |
2279 if options.issue: | 2290 if options.issue: |
2280 print "Warning: Private flag ignored when updating an existing issue." | 2291 print "Warning: Private flag ignored when updating an existing issue." |
2281 else: | 2292 else: |
2282 form_fields.append(("private", "1")) | 2293 form_fields.append(("private", "1")) |
2283 if options.send_patch: | 2294 if options.send_patch: |
2284 options.send_mail = True | 2295 options.send_mail = True |
2285 # If we're uploading base files, don't send the email before the uploads, so | |
2286 # that it contains the file status. | |
2287 if options.send_mail and options.download_base: | |
2288 form_fields.append(("send_mail", "1")) | |
2289 if not options.download_base: | 2296 if not options.download_base: |
2290 form_fields.append(("content_upload", "1")) | 2297 form_fields.append(("content_upload", "1")) |
2291 if len(data) > MAX_UPLOAD_SIZE: | 2298 if len(data) > MAX_UPLOAD_SIZE: |
2292 print "Patch is large, so uploading file patches separately." | 2299 print "Patch is large, so uploading file patches separately." |
2293 uploaded_diff_file = [] | 2300 uploaded_diff_file = [] |
2294 form_fields.append(("separate_patches", "1")) | 2301 form_fields.append(("separate_patches", "1")) |
2295 else: | 2302 else: |
2296 uploaded_diff_file = [("data", "data.diff", data)] | 2303 uploaded_diff_file = [("data", "data.diff", data)] |
2297 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) | 2304 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) |
2298 response_body = rpc_server.Send("/upload", body, content_type=ctype) | 2305 response_body = rpc_server.Send("/upload", body, content_type=ctype) |
(...skipping 14 matching lines...) Expand all Loading... |
2313 sys.exit(0) | 2320 sys.exit(0) |
2314 issue = msg[msg.rfind("/")+1:] | 2321 issue = msg[msg.rfind("/")+1:] |
2315 | 2322 |
2316 if not uploaded_diff_file: | 2323 if not uploaded_diff_file: |
2317 result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) | 2324 result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) |
2318 if not options.download_base: | 2325 if not options.download_base: |
2319 patches = result | 2326 patches = result |
2320 | 2327 |
2321 if not options.download_base: | 2328 if not options.download_base: |
2322 vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) | 2329 vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) |
2323 if options.send_mail: | 2330 |
2324 payload = "" | 2331 payload = {} # payload for final request |
2325 if options.send_patch: | 2332 if options.send_mail: |
2326 payload=urllib.urlencode({"attach_patch": "yes"}) | 2333 payload["send_mail"] = "yes" |
2327 rpc_server.Send("/" + issue + "/mail", payload=payload) | 2334 if options.send_patch: |
| 2335 payload["attach_patch"] = "yes" |
| 2336 payload = urllib.urlencode(payload) |
| 2337 rpc_server.Send("/" + issue + "/upload_complete/" + (patchset or ""), |
| 2338 payload=payload) |
2328 return issue, patchset | 2339 return issue, patchset |
2329 | 2340 |
2330 | 2341 |
2331 def main(): | 2342 def main(): |
2332 try: | 2343 try: |
2333 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" | 2344 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" |
2334 "%(lineno)s %(message)s ")) | 2345 "%(lineno)s %(message)s ")) |
2335 os.environ['LC_ALL'] = 'C' | 2346 os.environ['LC_ALL'] = 'C' |
2336 RealMain(sys.argv) | 2347 RealMain(sys.argv) |
2337 except KeyboardInterrupt: | 2348 except KeyboardInterrupt: |
2338 print | 2349 print |
2339 StatusUpdate("Interrupted.") | 2350 StatusUpdate("Interrupted.") |
2340 sys.exit(1) | 2351 sys.exit(1) |
2341 | 2352 |
2342 | 2353 |
2343 if __name__ == "__main__": | 2354 if __name__ == "__main__": |
2344 main() | 2355 main() |
OLD | NEW |