| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # coding: utf-8 | 2 # coding: utf-8 |
| 3 # | 3 # |
| 4 # Copyright 2007 Google Inc. | 4 # Copyright 2007 Google Inc. |
| 5 # | 5 # |
| 6 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 # 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. |
| 8 # You may obtain a copy of the License at | 8 # You may obtain a copy of the License at |
| 9 # | 9 # |
| 10 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 import keyring | 71 import keyring |
| 72 except ImportError: | 72 except ImportError: |
| 73 keyring = None | 73 keyring = None |
| 74 | 74 |
| 75 # The logging verbosity: | 75 # The logging verbosity: |
| 76 # 0: Errors only. | 76 # 0: Errors only. |
| 77 # 1: Status messages. | 77 # 1: Status messages. |
| 78 # 2: Info logs. | 78 # 2: Info logs. |
| 79 # 3: Debug logs. | 79 # 3: Debug logs. |
| 80 verbosity = 1 | 80 verbosity = 1 |
| 81 LOGGER = logging.getLogger('upload') |
| 81 | 82 |
| 82 # The account type used for authentication. | 83 # The account type used for authentication. |
| 83 # This line could be changed by the review server (see handler for | 84 # This line could be changed by the review server (see handler for |
| 84 # upload.py). | 85 # upload.py). |
| 85 AUTH_ACCOUNT_TYPE = "GOOGLE" | 86 AUTH_ACCOUNT_TYPE = "GOOGLE" |
| 86 | 87 |
| 87 # URL of the default review server. As for AUTH_ACCOUNT_TYPE, this line could be | 88 # URL of the default review server. As for AUTH_ACCOUNT_TYPE, this line could be |
| 88 # changed by the review server (see handler for upload.py). | 89 # changed by the review server (see handler for upload.py). |
| 89 DEFAULT_REVIEW_SERVER = "codereview.appspot.com" | 90 DEFAULT_REVIEW_SERVER = "codereview.appspot.com" |
| 90 | 91 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 not self.host.startswith("https://")): | 264 not self.host.startswith("https://")): |
| 264 self.host = "http://" + self.host | 265 self.host = "http://" + self.host |
| 265 self.host_override = host_override | 266 self.host_override = host_override |
| 266 self.auth_function = auth_function | 267 self.auth_function = auth_function |
| 267 self.authenticated = False | 268 self.authenticated = False |
| 268 self.extra_headers = extra_headers or {} | 269 self.extra_headers = extra_headers or {} |
| 269 self.save_cookies = save_cookies | 270 self.save_cookies = save_cookies |
| 270 self.account_type = account_type | 271 self.account_type = account_type |
| 271 self.opener = self._GetOpener() | 272 self.opener = self._GetOpener() |
| 272 if self.host_override: | 273 if self.host_override: |
| 273 logging.info("Server: %s; Host: %s", self.host, self.host_override) | 274 LOGGER.info("Server: %s; Host: %s", self.host, self.host_override) |
| 274 else: | 275 else: |
| 275 logging.info("Server: %s", self.host) | 276 LOGGER.info("Server: %s", self.host) |
| 276 | 277 |
| 277 def _GetOpener(self): | 278 def _GetOpener(self): |
| 278 """Returns an OpenerDirector for making HTTP requests. | 279 """Returns an OpenerDirector for making HTTP requests. |
| 279 | 280 |
| 280 Returns: | 281 Returns: |
| 281 A urllib2.OpenerDirector object. | 282 A urllib2.OpenerDirector object. |
| 282 """ | 283 """ |
| 283 raise NotImplementedError() | 284 raise NotImplementedError() |
| 284 | 285 |
| 285 def _CreateRequest(self, url, data=None): | 286 def _CreateRequest(self, url, data=None): |
| 286 """Creates a new urllib request.""" | 287 """Creates a new urllib request.""" |
| 287 logging.debug("Creating request for: '%s' with payload:\n%s", url, data) | 288 LOGGER.debug("Creating request for: '%s' with payload:\n%s", url, data) |
| 288 req = urllib2.Request(url, data=data, headers={"Accept": "text/plain"}) | 289 req = urllib2.Request(url, data=data, headers={"Accept": "text/plain"}) |
| 289 if self.host_override: | 290 if self.host_override: |
| 290 req.add_header("Host", self.host_override) | 291 req.add_header("Host", self.host_override) |
| 291 for key, value in self.extra_headers.iteritems(): | 292 for key, value in self.extra_headers.iteritems(): |
| 292 req.add_header(key, value) | 293 req.add_header(key, value) |
| 293 return req | 294 return req |
| 294 | 295 |
| 295 def _GetAuthToken(self, email, password): | 296 def _GetAuthToken(self, email, password): |
| 296 """Uses ClientLogin to authenticate the user, returning an auth token. | 297 """Uses ClientLogin to authenticate the user, returning an auth token. |
| 297 | 298 |
| (...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 OAuth, this opens a page in the user's browser to obtain a token. | 925 OAuth, this opens a page in the user's browser to obtain a token. |
| 925 | 926 |
| 926 Returns: | 927 Returns: |
| 927 A new HttpRpcServer, on which RPC calls can be made. | 928 A new HttpRpcServer, on which RPC calls can be made. |
| 928 """ | 929 """ |
| 929 # If this is the dev_appserver, use fake authentication. | 930 # If this is the dev_appserver, use fake authentication. |
| 930 host = (host_override or server).lower() | 931 host = (host_override or server).lower() |
| 931 if re.match(r'(http://)?localhost([:/]|$)', host): | 932 if re.match(r'(http://)?localhost([:/]|$)', host): |
| 932 if email is None: | 933 if email is None: |
| 933 email = "test@example.com" | 934 email = "test@example.com" |
| 934 logging.info("Using debug user %s. Override with --email" % email) | 935 LOGGER.info("Using debug user %s. Override with --email" % email) |
| 935 server = HttpRpcServer( | 936 server = HttpRpcServer( |
| 936 server, | 937 server, |
| 937 lambda: (email, "password"), | 938 lambda: (email, "password"), |
| 938 host_override=host_override, | 939 host_override=host_override, |
| 939 extra_headers={"Cookie": | 940 extra_headers={"Cookie": |
| 940 'dev_appserver_login="%s:False"' % email}, | 941 'dev_appserver_login="%s:False"' % email}, |
| 941 save_cookies=save_cookies, | 942 save_cookies=save_cookies, |
| 942 account_type=account_type) | 943 account_type=account_type) |
| 943 # Don't try to talk to ClientLogin. | 944 # Don't try to talk to ClientLogin. |
| 944 server.authenticated = True | 945 server.authenticated = True |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 | 1011 |
| 1011 Args: | 1012 Args: |
| 1012 command: Command to execute. | 1013 command: Command to execute. |
| 1013 print_output: If True, the output is printed to stdout. | 1014 print_output: If True, the output is printed to stdout. |
| 1014 If False, both stdout and stderr are ignored. | 1015 If False, both stdout and stderr are ignored. |
| 1015 universal_newlines: Use universal_newlines flag (default: True). | 1016 universal_newlines: Use universal_newlines flag (default: True). |
| 1016 | 1017 |
| 1017 Returns: | 1018 Returns: |
| 1018 Tuple (stdout, stderr, return code) | 1019 Tuple (stdout, stderr, return code) |
| 1019 """ | 1020 """ |
| 1020 logging.info("Running %s", command) | 1021 LOGGER.info("Running %s", command) |
| 1021 env = env.copy() | 1022 env = env.copy() |
| 1022 env['LC_MESSAGES'] = 'C' | 1023 env['LC_MESSAGES'] = 'C' |
| 1023 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 1024 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 1024 shell=use_shell, universal_newlines=universal_newlines, | 1025 shell=use_shell, universal_newlines=universal_newlines, |
| 1025 env=env) | 1026 env=env) |
| 1026 if print_output: | 1027 if print_output: |
| 1027 output_array = [] | 1028 output_array = [] |
| 1028 while True: | 1029 while True: |
| 1029 line = p.stdout.readline() | 1030 line = p.stdout.readline() |
| 1030 if not line: | 1031 if not line: |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1272 if netloc == "svn.python.org" and scheme == "svn+ssh": | 1273 if netloc == "svn.python.org" and scheme == "svn+ssh": |
| 1273 path = "projects" + path | 1274 path = "projects" + path |
| 1274 scheme = "http" | 1275 scheme = "http" |
| 1275 guess = "Python " | 1276 guess = "Python " |
| 1276 elif netloc.endswith(".googlecode.com"): | 1277 elif netloc.endswith(".googlecode.com"): |
| 1277 scheme = "http" | 1278 scheme = "http" |
| 1278 guess = "Google Code " | 1279 guess = "Google Code " |
| 1279 path = path + "/" | 1280 path = path + "/" |
| 1280 base = urlparse.urlunparse((scheme, netloc, path, params, | 1281 base = urlparse.urlunparse((scheme, netloc, path, params, |
| 1281 query, fragment)) | 1282 query, fragment)) |
| 1282 logging.info("Guessed %sbase = %s", guess, base) | 1283 LOGGER.info("Guessed %sbase = %s", guess, base) |
| 1283 return base | 1284 return base |
| 1284 if required: | 1285 if required: |
| 1285 ErrorExit("Can't find URL in output from svn info") | 1286 ErrorExit("Can't find URL in output from svn info") |
| 1286 return None | 1287 return None |
| 1287 | 1288 |
| 1288 def _GetInfo(self, key): | 1289 def _GetInfo(self, key): |
| 1289 """Parses 'svn info' for current dir. Returns value for key or None""" | 1290 """Parses 'svn info' for current dir. Returns value for key or None""" |
| 1290 for line in RunShell(["svn", "info"]).splitlines(): | 1291 for line in RunShell(["svn", "info"]).splitlines(): |
| 1291 if line.startswith(key + ": "): | 1292 if line.startswith(key + ": "): |
| 1292 return line.split(":", 1)[1].strip() | 1293 return line.split(":", 1)[1].strip() |
| 1293 | 1294 |
| 1294 def _EscapeFilename(self, filename): | 1295 def _EscapeFilename(self, filename): |
| 1295 """Escapes filename for SVN commands.""" | 1296 """Escapes filename for SVN commands.""" |
| 1296 if "@" in filename and not filename.endswith("@"): | 1297 if "@" in filename and not filename.endswith("@"): |
| 1297 filename = "%s@" % filename | 1298 filename = "%s@" % filename |
| 1298 return filename | 1299 return filename |
| 1299 | 1300 |
| 1300 def GenerateDiff(self, args): | 1301 def GenerateDiff(self, args): |
| 1301 cmd = ["svn", "diff"] | 1302 cmd = ["svn", "diff"] |
| 1302 if self.options.revision: | 1303 if self.options.revision: |
| 1303 cmd += ["-r", self.options.revision] | 1304 cmd += ["-r", self.options.revision] |
| 1304 cmd.extend(args) | 1305 cmd.extend(args) |
| 1305 data = RunShell(cmd) | 1306 data = RunShell(cmd) |
| 1306 count = 0 | 1307 count = 0 |
| 1307 for line in data.splitlines(): | 1308 for line in data.splitlines(): |
| 1308 if line.startswith("Index:") or line.startswith("Property changes on:"): | 1309 if line.startswith("Index:") or line.startswith("Property changes on:"): |
| 1309 count += 1 | 1310 count += 1 |
| 1310 logging.info(line) | 1311 LOGGER.info(line) |
| 1311 if not count: | 1312 if not count: |
| 1312 ErrorExit("No valid patches found in output from svn diff") | 1313 ErrorExit("No valid patches found in output from svn diff") |
| 1313 return data | 1314 return data |
| 1314 | 1315 |
| 1315 def _CollapseKeywords(self, content, keyword_str): | 1316 def _CollapseKeywords(self, content, keyword_str): |
| 1316 """Collapses SVN keywords.""" | 1317 """Collapses SVN keywords.""" |
| 1317 # svn cat translates keywords but svn diff doesn't. As a result of this | 1318 # svn cat translates keywords but svn diff doesn't. As a result of this |
| 1318 # behavior patching.PatchChunks() fails with a chunk mismatch error. | 1319 # behavior patching.PatchChunks() fails with a chunk mismatch error. |
| 1319 # This part was originally written by the Review Board development team | 1320 # This part was originally written by the Review Board development team |
| 1320 # who had the same problem (http://reviews.review-board.org/r/276/). | 1321 # who had the same problem (http://reviews.review-board.org/r/276/). |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1729 if self.options.revision: | 1730 if self.options.revision: |
| 1730 cmd += ["-r", self.options.revision] | 1731 cmd += ["-r", self.options.revision] |
| 1731 | 1732 |
| 1732 cmd.extend(extra_args) | 1733 cmd.extend(extra_args) |
| 1733 data, retcode = RunShellWithReturnCode(cmd) | 1734 data, retcode = RunShellWithReturnCode(cmd) |
| 1734 count = 0 | 1735 count = 0 |
| 1735 if retcode in [0, 1]: | 1736 if retcode in [0, 1]: |
| 1736 for line in data.splitlines(): | 1737 for line in data.splitlines(): |
| 1737 if line.startswith("Index:"): | 1738 if line.startswith("Index:"): |
| 1738 count += 1 | 1739 count += 1 |
| 1739 logging.info(line) | 1740 LOGGER.info(line) |
| 1740 | 1741 |
| 1741 if not count: | 1742 if not count: |
| 1742 ErrorExit("No valid patches found in output from cvs diff") | 1743 ErrorExit("No valid patches found in output from cvs diff") |
| 1743 | 1744 |
| 1744 return data | 1745 return data |
| 1745 | 1746 |
| 1746 def GetUnknownFiles(self): | 1747 def GetUnknownFiles(self): |
| 1747 data, retcode = RunShellWithReturnCode(["cvs", "diff"]) | 1748 data, retcode = RunShellWithReturnCode(["cvs", "diff"]) |
| 1748 if retcode not in [0, 1]: | 1749 if retcode not in [0, 1]: |
| 1749 ErrorExit("Got error status from 'cvs diff':\n%s" % (data,)) | 1750 ErrorExit("Got error status from 'cvs diff':\n%s" % (data,)) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1791 if m: | 1792 if m: |
| 1792 # Modify line to make it look like as it comes from svn diff. | 1793 # Modify line to make it look like as it comes from svn diff. |
| 1793 # With this modification no changes on the server side are required | 1794 # With this modification no changes on the server side are required |
| 1794 # to make upload.py work with Mercurial repos. | 1795 # to make upload.py work with Mercurial repos. |
| 1795 # NOTE: for proper handling of moved/copied files, we have to use | 1796 # NOTE: for proper handling of moved/copied files, we have to use |
| 1796 # the second filename. | 1797 # the second filename. |
| 1797 filename = m.group(2) | 1798 filename = m.group(2) |
| 1798 svndiff.append("Index: %s" % filename) | 1799 svndiff.append("Index: %s" % filename) |
| 1799 svndiff.append("=" * 67) | 1800 svndiff.append("=" * 67) |
| 1800 filecount += 1 | 1801 filecount += 1 |
| 1801 logging.info(line) | 1802 LOGGER.info(line) |
| 1802 else: | 1803 else: |
| 1803 svndiff.append(line) | 1804 svndiff.append(line) |
| 1804 if not filecount: | 1805 if not filecount: |
| 1805 ErrorExit("No valid patches found in output from hg diff") | 1806 ErrorExit("No valid patches found in output from hg diff") |
| 1806 return "\n".join(svndiff) + "\n" | 1807 return "\n".join(svndiff) + "\n" |
| 1807 | 1808 |
| 1808 def GetUnknownFiles(self): | 1809 def GetUnknownFiles(self): |
| 1809 """Return a list of files unknown to the VCS.""" | 1810 """Return a list of files unknown to the VCS.""" |
| 1810 args = [] | 1811 args = [] |
| 1811 status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], | 1812 status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], |
| (...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2520 "For more help, see " | 2521 "For more help, see " |
| 2521 "http://code.google.com/p/rietveld/wiki/CodeReviewHelp" | 2522 "http://code.google.com/p/rietveld/wiki/CodeReviewHelp" |
| 2522 ) | 2523 ) |
| 2523 parser.option_groups.remove(parser.get_option_group('--p4_port')) | 2524 parser.option_groups.remove(parser.get_option_group('--p4_port')) |
| 2524 parser.print_help() | 2525 parser.print_help() |
| 2525 sys.exit(0) | 2526 sys.exit(0) |
| 2526 | 2527 |
| 2527 global verbosity | 2528 global verbosity |
| 2528 verbosity = options.verbose | 2529 verbosity = options.verbose |
| 2529 if verbosity >= 3: | 2530 if verbosity >= 3: |
| 2530 logging.getLogger().setLevel(logging.DEBUG) | 2531 LOGGER.setLevel(logging.DEBUG) |
| 2531 elif verbosity >= 2: | 2532 elif verbosity >= 2: |
| 2532 logging.getLogger().setLevel(logging.INFO) | 2533 LOGGER.setLevel(logging.INFO) |
| 2533 | 2534 |
| 2534 vcs = GuessVCS(options) | 2535 vcs = GuessVCS(options) |
| 2535 | 2536 |
| 2536 base = options.base_url | 2537 base = options.base_url |
| 2537 if isinstance(vcs, SubversionVCS): | 2538 if isinstance(vcs, SubversionVCS): |
| 2538 # Guessing the base field is only supported for Subversion. | 2539 # Guessing the base field is only supported for Subversion. |
| 2539 # Note: Fetching base files may become deprecated in future releases. | 2540 # Note: Fetching base files may become deprecated in future releases. |
| 2540 guessed_base = vcs.GuessBase(options.download_base) | 2541 guessed_base = vcs.GuessBase(options.download_base) |
| 2541 if base: | 2542 if base: |
| 2542 if guessed_base and base != guessed_base: | 2543 if guessed_base and base != guessed_base: |
| 2543 print "Using base URL \"%s\" from --base_url instead of \"%s\"" % \ | 2544 print "Using base URL \"%s\" from --base_url instead of \"%s\"" % \ |
| 2544 (base, guessed_base) | 2545 (base, guessed_base) |
| 2545 else: | 2546 else: |
| 2546 base = guessed_base | 2547 base = guessed_base |
| 2547 | 2548 |
| 2548 if not base and options.download_base: | 2549 if not base and options.download_base: |
| 2549 options.download_base = True | 2550 options.download_base = True |
| 2550 logging.info("Enabled upload of base file") | 2551 LOGGER.info("Enabled upload of base file") |
| 2551 if not options.assume_yes: | 2552 if not options.assume_yes: |
| 2552 vcs.CheckForUnknownFiles() | 2553 vcs.CheckForUnknownFiles() |
| 2553 if data is None: | 2554 if data is None: |
| 2554 data = vcs.GenerateDiff(args) | 2555 data = vcs.GenerateDiff(args) |
| 2555 data = vcs.PostProcessDiff(data) | 2556 data = vcs.PostProcessDiff(data) |
| 2556 if options.print_diffs: | 2557 if options.print_diffs: |
| 2557 print "Rietveld diff start:*****" | 2558 print "Rietveld diff start:*****" |
| 2558 print data | 2559 print data |
| 2559 print "Rietveld diff end:*****" | 2560 print "Rietveld diff end:*****" |
| 2560 files = vcs.GetBaseFiles(data) | 2561 files = vcs.GetBaseFiles(data) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2572 options.open_oauth2_local_webbrowser) | 2573 options.open_oauth2_local_webbrowser) |
| 2573 form_fields = [] | 2574 form_fields = [] |
| 2574 | 2575 |
| 2575 repo_guid = vcs.GetGUID() | 2576 repo_guid = vcs.GetGUID() |
| 2576 if repo_guid: | 2577 if repo_guid: |
| 2577 form_fields.append(("repo_guid", repo_guid)) | 2578 form_fields.append(("repo_guid", repo_guid)) |
| 2578 if base: | 2579 if base: |
| 2579 b = urlparse.urlparse(base) | 2580 b = urlparse.urlparse(base) |
| 2580 username, netloc = urllib.splituser(b.netloc) | 2581 username, netloc = urllib.splituser(b.netloc) |
| 2581 if username: | 2582 if username: |
| 2582 logging.info("Removed username from base URL") | 2583 LOGGER.info("Removed username from base URL") |
| 2583 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, | 2584 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, |
| 2584 b.query, b.fragment)) | 2585 b.query, b.fragment)) |
| 2585 form_fields.append(("base", base)) | 2586 form_fields.append(("base", base)) |
| 2586 if options.issue: | 2587 if options.issue: |
| 2587 form_fields.append(("issue", str(options.issue))) | 2588 form_fields.append(("issue", str(options.issue))) |
| 2588 if options.email: | 2589 if options.email: |
| 2589 form_fields.append(("user", options.email)) | 2590 form_fields.append(("user", options.email)) |
| 2590 if options.reviewers: | 2591 if options.reviewers: |
| 2591 for reviewer in options.reviewers.split(','): | 2592 for reviewer in options.reviewers.split(','): |
| 2592 CheckReviewer(reviewer) | 2593 CheckReviewer(reviewer) |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2699 os.environ['LC_ALL'] = 'C' | 2700 os.environ['LC_ALL'] = 'C' |
| 2700 RealMain(sys.argv) | 2701 RealMain(sys.argv) |
| 2701 except KeyboardInterrupt: | 2702 except KeyboardInterrupt: |
| 2702 print | 2703 print |
| 2703 StatusUpdate("Interrupted.") | 2704 StatusUpdate("Interrupted.") |
| 2704 sys.exit(1) | 2705 sys.exit(1) |
| 2705 | 2706 |
| 2706 | 2707 |
| 2707 if __name__ == "__main__": | 2708 if __name__ == "__main__": |
| 2708 main() | 2709 main() |
| OLD | NEW |