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