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 |