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 16 matching lines...) Expand all Loading... |
27 Subversion | 27 Subversion |
28 Perforce | 28 Perforce |
29 CVS | 29 CVS |
30 | 30 |
31 It is important for Git/Mercurial users to specify a tree/node/branch to diff | 31 It is important for Git/Mercurial users to specify a tree/node/branch to diff |
32 against by using the '--rev' option. | 32 against by using the '--rev' option. |
33 """ | 33 """ |
34 # This code is derived from appcfg.py in the App Engine SDK (open source), | 34 # This code is derived from appcfg.py in the App Engine SDK (open source), |
35 # and from ASPN recipe #146306. | 35 # and from ASPN recipe #146306. |
36 | 36 |
| 37 from __future__ import print_function |
| 38 |
37 import ConfigParser | 39 import ConfigParser |
38 import cookielib | 40 import cookielib |
39 import errno | 41 import errno |
40 import fnmatch | 42 import fnmatch |
41 import getpass | 43 import getpass |
42 import logging | 44 import logging |
43 import marshal | 45 import marshal |
44 import mimetypes | 46 import mimetypes |
45 import optparse | 47 import optparse |
46 import os | 48 import os |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 163 |
162 def StatusUpdate(msg): | 164 def StatusUpdate(msg): |
163 """Print a status message to stdout. | 165 """Print a status message to stdout. |
164 | 166 |
165 If 'verbosity' is greater than 0, print the message. | 167 If 'verbosity' is greater than 0, print the message. |
166 | 168 |
167 Args: | 169 Args: |
168 msg: The string to print. | 170 msg: The string to print. |
169 """ | 171 """ |
170 if verbosity > 0: | 172 if verbosity > 0: |
171 print msg | 173 print(msg) |
172 | 174 |
173 | 175 |
174 def ErrorExit(msg): | 176 def ErrorExit(msg): |
175 """Print an error message to stderr and exit.""" | 177 """Print an error message to stderr and exit.""" |
176 print >> sys.stderr, msg | 178 print(msg, file=sys.stderr) |
177 sys.exit(1) | 179 sys.exit(1) |
178 | 180 |
179 | 181 |
180 class ClientLoginError(urllib2.HTTPError): | 182 class ClientLoginError(urllib2.HTTPError): |
181 """Raised to indicate there was an error authenticating with ClientLogin.""" | 183 """Raised to indicate there was an error authenticating with ClientLogin.""" |
182 | 184 |
183 def __init__(self, url, code, msg, headers, args): | 185 def __init__(self, url, code, msg, headers, args): |
184 urllib2.HTTPError.__init__(self, url, code, msg, headers, None) | 186 urllib2.HTTPError.__init__(self, url, code, msg, headers, None) |
185 self.args = args | 187 self.args = args |
186 self._reason = args["Error"] | 188 self._reason = args["Error"] |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 "adel": "AccountDeleted", | 353 "adel": "AccountDeleted", |
352 "adis": "AccountDisabled", | 354 "adis": "AccountDisabled", |
353 "sdis": "ServiceDisabled", | 355 "sdis": "ServiceDisabled", |
354 "ire": "ServiceUnavailable", | 356 "ire": "ServiceUnavailable", |
355 } | 357 } |
356 auth_token = self._GetAuthToken(credentials[0], credentials[1], | 358 auth_token = self._GetAuthToken(credentials[0], credentials[1], |
357 internal=True) | 359 internal=True) |
358 except ClientLoginError, exc: | 360 except ClientLoginError, exc: |
359 e = exc | 361 e = exc |
360 if e: | 362 if e: |
361 print >> sys.stderr, '' | 363 print('', file=sys.stderr) |
362 error_message = e.reason | 364 error_message = e.reason |
363 if error_map: | 365 if error_map: |
364 error_message = error_map.get(error_message, error_message) | 366 error_message = error_map.get(error_message, error_message) |
365 if error_message == "BadAuthentication": | 367 if error_message == "BadAuthentication": |
366 if e.info == "InvalidSecondFactor": | 368 if e.info == "InvalidSecondFactor": |
367 print >> sys.stderr, ( | 369 print >> sys.stderr, ( |
368 "Use an application-specific password instead " | 370 "Use an application-specific password instead " |
369 "of your regular account password.\n" | 371 "of your regular account password.\n" |
370 "See http://www.google.com/" | 372 "See http://www.google.com/" |
371 "support/accounts/bin/answer.py?answer=185833") | 373 "support/accounts/bin/answer.py?answer=185833") |
372 else: | 374 else: |
373 print >> sys.stderr, "Invalid username or password." | 375 print("Invalid username or password.", file=sys.stderr) |
374 elif error_message == "CaptchaRequired": | 376 elif error_message == "CaptchaRequired": |
375 print >> sys.stderr, ( | 377 print >> sys.stderr, ( |
376 "Please go to\n" | 378 "Please go to\n" |
377 "https://www.google.com/accounts/DisplayUnlockCaptcha\n" | 379 "https://www.google.com/accounts/DisplayUnlockCaptcha\n" |
378 "and verify you are a human. Then try again.\n" | 380 "and verify you are a human. Then try again.\n" |
379 "If you are using a Google Apps account the URL is:\n" | 381 "If you are using a Google Apps account the URL is:\n" |
380 "https://www.google.com/a/yourdomain.com/UnlockCaptcha") | 382 "https://www.google.com/a/yourdomain.com/UnlockCaptcha") |
381 elif error_message == "NotVerified": | 383 elif error_message == "NotVerified": |
382 print >> sys.stderr, "Account not verified." | 384 print("Account not verified.", file=sys.stderr) |
383 elif error_message == "TermsNotAgreed": | 385 elif error_message == "TermsNotAgreed": |
384 print >> sys.stderr, "User has not agreed to TOS." | 386 print("User has not agreed to TOS.", file=sys.stderr) |
385 elif error_message == "AccountDeleted": | 387 elif error_message == "AccountDeleted": |
386 print >> sys.stderr, "The user account has been deleted." | 388 print("The user account has been deleted.", file=sys.stderr) |
387 elif error_message == "AccountDisabled": | 389 elif error_message == "AccountDisabled": |
388 print >> sys.stderr, "The user account has been disabled." | 390 print("The user account has been disabled.", file=sys.stderr) |
389 break | 391 break |
390 elif error_message == "ServiceDisabled": | 392 elif error_message == "ServiceDisabled": |
391 print >> sys.stderr, ("The user's access to the service has been " | 393 print("The user's access to the service has been disabled.", |
392 "disabled.") | 394 file=sys.stderr) |
393 elif error_message == "ServiceUnavailable": | 395 elif error_message == "ServiceUnavailable": |
394 print >> sys.stderr, "The service is not available; try again later." | 396 print("The service is not available; try again later.", |
| 397 file=sys.stderr) |
395 else: | 398 else: |
396 # Unknown error. | 399 # Unknown error. |
397 raise e | 400 raise e |
398 print >> sys.stderr, '' | 401 print('', file=sys.stderr) |
399 continue | 402 continue |
400 self._GetAuthCookie(auth_token) | 403 self._GetAuthCookie(auth_token) |
401 return | 404 return |
402 | 405 |
403 def Send(self, request_path, payload=None, | 406 def Send(self, request_path, payload=None, |
404 content_type="application/octet-stream", | 407 content_type="application/octet-stream", |
405 timeout=None, | 408 timeout=None, |
406 extra_headers=None, | 409 extra_headers=None, |
407 **kwargs): | 410 **kwargs): |
408 """Sends an RPC and returns the response. | 411 """Sends an RPC and returns the response. |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 email = self.email | 716 email = self.email |
714 if email is None: | 717 if email is None: |
715 email = GetEmail("Email (login for uploading to %s)" % self.server) | 718 email = GetEmail("Email (login for uploading to %s)" % self.server) |
716 password = None | 719 password = None |
717 if keyring and not email in self.accounts_seen: | 720 if keyring and not email in self.accounts_seen: |
718 try: | 721 try: |
719 password = keyring.get_password(self.host, email) | 722 password = keyring.get_password(self.host, email) |
720 except: | 723 except: |
721 # Sadly, we have to trap all errors here as | 724 # Sadly, we have to trap all errors here as |
722 # gnomekeyring.IOError inherits from object. :/ | 725 # gnomekeyring.IOError inherits from object. :/ |
723 print "Failed to get password from keyring" | 726 print("Failed to get password from keyring") |
724 keyring = None | 727 keyring = None |
725 if password is not None: | 728 if password is not None: |
726 print "Using password from system keyring." | 729 print("Using password from system keyring.") |
727 self.accounts_seen.add(email) | 730 self.accounts_seen.add(email) |
728 else: | 731 else: |
729 password = getpass.getpass("Password for %s: " % email) | 732 password = getpass.getpass("Password for %s: " % email) |
730 if keyring: | 733 if keyring: |
731 answer = raw_input("Store password in system keyring?(y/N) ").strip() | 734 answer = raw_input("Store password in system keyring?(y/N) ").strip() |
732 if answer == "y": | 735 if answer == "y": |
733 keyring.set_password(self.host, email, password) | 736 keyring.set_password(self.host, email, password) |
734 self.accounts_seen.add(email) | 737 self.accounts_seen.add(email) |
735 return (email, password) | 738 return (email, password) |
736 | 739 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 | 916 |
914 def GetUnknownFiles(self): | 917 def GetUnknownFiles(self): |
915 """Return a list of files unknown to the VCS.""" | 918 """Return a list of files unknown to the VCS.""" |
916 raise NotImplementedError( | 919 raise NotImplementedError( |
917 "abstract method -- subclass %s must override" % self.__class__) | 920 "abstract method -- subclass %s must override" % self.__class__) |
918 | 921 |
919 def CheckForUnknownFiles(self): | 922 def CheckForUnknownFiles(self): |
920 """Show an "are you sure?" prompt if there are unknown files.""" | 923 """Show an "are you sure?" prompt if there are unknown files.""" |
921 unknown_files = self.GetUnknownFiles() | 924 unknown_files = self.GetUnknownFiles() |
922 if unknown_files: | 925 if unknown_files: |
923 print "The following files are not added to version control:" | 926 print("The following files are not added to version control:") |
924 for line in unknown_files: | 927 for line in unknown_files: |
925 print line | 928 print(line) |
926 prompt = "Are you sure to continue?(y/N) " | 929 prompt = "Are you sure to continue?(y/N) " |
927 answer = raw_input(prompt).strip() | 930 answer = raw_input(prompt).strip() |
928 if answer != "y": | 931 if answer != "y": |
929 ErrorExit("User aborted") | 932 ErrorExit("User aborted") |
930 | 933 |
931 def GetBaseFile(self, filename): | 934 def GetBaseFile(self, filename): |
932 """Get the content of the upstream version of a file. | 935 """Get the content of the upstream version of a file. |
933 | 936 |
934 Returns: | 937 Returns: |
935 A tuple (base_content, new_content, is_binary, status) | 938 A tuple (base_content, new_content, is_binary, status) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1022 if base_content != None: | 1025 if base_content != None: |
1023 t = thread_pool.apply_async(UploadFile, args=(filename, | 1026 t = thread_pool.apply_async(UploadFile, args=(filename, |
1024 file_id, base_content, is_binary, status, True)) | 1027 file_id, base_content, is_binary, status, True)) |
1025 threads.append(t) | 1028 threads.append(t) |
1026 if new_content != None: | 1029 if new_content != None: |
1027 t = thread_pool.apply_async(UploadFile, args=(filename, | 1030 t = thread_pool.apply_async(UploadFile, args=(filename, |
1028 file_id, new_content, is_binary, status, False)) | 1031 file_id, new_content, is_binary, status, False)) |
1029 threads.append(t) | 1032 threads.append(t) |
1030 | 1033 |
1031 for t in threads: | 1034 for t in threads: |
1032 print t.get(timeout=60) | 1035 print(t.get(timeout=60)) |
1033 | 1036 |
1034 def IsImage(self, filename): | 1037 def IsImage(self, filename): |
1035 """Returns true if the filename has an image extension.""" | 1038 """Returns true if the filename has an image extension.""" |
1036 mimetype = mimetypes.guess_type(filename)[0] | 1039 mimetype = mimetypes.guess_type(filename)[0] |
1037 if not mimetype: | 1040 if not mimetype: |
1038 return False | 1041 return False |
1039 return (mimetype.startswith("image/") and | 1042 return (mimetype.startswith("image/") and |
1040 not mimetype.startswith("image/svg")) | 1043 not mimetype.startswith("image/svg")) |
1041 | 1044 |
1042 def IsBinaryData(self, data): | 1045 def IsBinaryData(self, data): |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1696 | 1699 |
1697 def ConfirmLogin(): | 1700 def ConfirmLogin(): |
1698 # Make sure we have a valid perforce session | 1701 # Make sure we have a valid perforce session |
1699 while True: | 1702 while True: |
1700 data, retcode = self.RunPerforceCommandWithReturnCode( | 1703 data, retcode = self.RunPerforceCommandWithReturnCode( |
1701 ["login", "-s"], marshal_output=True) | 1704 ["login", "-s"], marshal_output=True) |
1702 if not data: | 1705 if not data: |
1703 ErrorExit("Error checking perforce login") | 1706 ErrorExit("Error checking perforce login") |
1704 if not retcode and (not "code" in data or data["code"] != "error"): | 1707 if not retcode and (not "code" in data or data["code"] != "error"): |
1705 break | 1708 break |
1706 print "Enter perforce password: " | 1709 print("Enter perforce password: ") |
1707 self.RunPerforceCommandWithReturnCode(["login"]) | 1710 self.RunPerforceCommandWithReturnCode(["login"]) |
1708 | 1711 |
1709 super(PerforceVCS, self).__init__(options) | 1712 super(PerforceVCS, self).__init__(options) |
1710 | 1713 |
1711 self.p4_changelist = options.p4_changelist | 1714 self.p4_changelist = options.p4_changelist |
1712 if not self.p4_changelist: | 1715 if not self.p4_changelist: |
1713 ErrorExit("A changelist id is required") | 1716 ErrorExit("A changelist id is required") |
1714 if (options.revision): | 1717 if (options.revision): |
1715 ErrorExit("--rev is not supported for perforce") | 1718 ErrorExit("--rev is not supported for perforce") |
1716 | 1719 |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2076 sys.exit(1) | 2079 sys.exit(1) |
2077 return ("Uploaded patch for " + filename, [lines[1], filename]) | 2080 return ("Uploaded patch for " + filename, [lines[1], filename]) |
2078 | 2081 |
2079 threads = [] | 2082 threads = [] |
2080 thread_pool = ThreadPool(options.num_upload_threads) | 2083 thread_pool = ThreadPool(options.num_upload_threads) |
2081 | 2084 |
2082 patches = SplitPatch(data) | 2085 patches = SplitPatch(data) |
2083 rv = [] | 2086 rv = [] |
2084 for patch in patches: | 2087 for patch in patches: |
2085 if len(patch[1]) > MAX_UPLOAD_SIZE: | 2088 if len(patch[1]) > MAX_UPLOAD_SIZE: |
2086 print ("Not uploading the patch for " + patch[0] + | 2089 print("Not uploading the patch for %s because the file is too large." % |
2087 " because the file is too large.") | 2090 (patch[0],)) |
2088 continue | 2091 continue |
2089 | 2092 |
2090 filename = patch[0] | 2093 filename = patch[0] |
2091 data = patch[1] | 2094 data = patch[1] |
2092 | 2095 |
2093 t = thread_pool.apply_async(UploadFile, args=(filename, data)) | 2096 t = thread_pool.apply_async(UploadFile, args=(filename, data)) |
2094 threads.append(t) | 2097 threads.append(t) |
2095 | 2098 |
2096 for t in threads: | 2099 for t in threads: |
2097 result = t.get(timeout=60) | 2100 result = t.get(timeout=60) |
2098 print result[0] | 2101 print(result[0]) |
2099 rv.append(result[1]) | 2102 rv.append(result[1]) |
2100 | 2103 |
2101 return rv | 2104 return rv |
2102 | 2105 |
2103 | 2106 |
2104 def GuessVCSName(options): | 2107 def GuessVCSName(options): |
2105 """Helper to guess the version control system. | 2108 """Helper to guess the version control system. |
2106 | 2109 |
2107 This examines the current directory, guesses which VersionControlSystem | 2110 This examines the current directory, guesses which VersionControlSystem |
2108 we're using, and returns an string indicating which VCS is detected. | 2111 we're using, and returns an string indicating which VCS is detected. |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2365 | 2368 |
2366 vcs = GuessVCS(options) | 2369 vcs = GuessVCS(options) |
2367 | 2370 |
2368 base = options.base_url | 2371 base = options.base_url |
2369 if isinstance(vcs, SubversionVCS): | 2372 if isinstance(vcs, SubversionVCS): |
2370 # Guessing the base field is only supported for Subversion. | 2373 # Guessing the base field is only supported for Subversion. |
2371 # Note: Fetching base files may become deprecated in future releases. | 2374 # Note: Fetching base files may become deprecated in future releases. |
2372 guessed_base = vcs.GuessBase(options.download_base) | 2375 guessed_base = vcs.GuessBase(options.download_base) |
2373 if base: | 2376 if base: |
2374 if guessed_base and base != guessed_base: | 2377 if guessed_base and base != guessed_base: |
2375 print "Using base URL \"%s\" from --base_url instead of \"%s\"" % \ | 2378 print("Using base URL \"%s\" from --base_url instead of \"%s\"" % |
2376 (base, guessed_base) | 2379 (base, guessed_base)) |
2377 else: | 2380 else: |
2378 base = guessed_base | 2381 base = guessed_base |
2379 | 2382 |
2380 if not base and options.download_base: | 2383 if not base and options.download_base: |
2381 options.download_base = True | 2384 options.download_base = True |
2382 LOGGER.info("Enabled upload of base file") | 2385 LOGGER.info("Enabled upload of base file") |
2383 if not options.assume_yes: | 2386 if not options.assume_yes: |
2384 vcs.CheckForUnknownFiles() | 2387 vcs.CheckForUnknownFiles() |
2385 if data is None: | 2388 if data is None: |
2386 data = vcs.GenerateDiff(args) | 2389 data = vcs.GenerateDiff(args) |
2387 data = vcs.PostProcessDiff(data) | 2390 data = vcs.PostProcessDiff(data) |
2388 if options.print_diffs: | 2391 if options.print_diffs: |
2389 print "Rietveld diff start:*****" | 2392 print("Rietveld diff start:*****") |
2390 print data | 2393 print(data) |
2391 print "Rietveld diff end:*****" | 2394 print("Rietveld diff end:*****") |
2392 files = vcs.GetBaseFiles(data) | 2395 files = vcs.GetBaseFiles(data) |
2393 if verbosity >= 1: | 2396 if verbosity >= 1: |
2394 print "Upload server:", options.server, "(change with -s/--server)" | 2397 print("Upload server:", options.server, "(change with -s/--server)") |
2395 | 2398 |
2396 auth_config = auth.extract_auth_config_from_options(options) | 2399 auth_config = auth.extract_auth_config_from_options(options) |
2397 rpc_server = GetRpcServer(options.server, auth_config, options.email) | 2400 rpc_server = GetRpcServer(options.server, auth_config, options.email) |
2398 form_fields = [] | 2401 form_fields = [] |
2399 | 2402 |
2400 repo_guid = vcs.GetGUID() | 2403 repo_guid = vcs.GetGUID() |
2401 if repo_guid: | 2404 if repo_guid: |
2402 form_fields.append(("repo_guid", repo_guid)) | 2405 form_fields.append(("repo_guid", repo_guid)) |
2403 if base: | 2406 if base: |
2404 b = urlparse.urlparse(base) | 2407 b = urlparse.urlparse(base) |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2470 base_hashes = "" | 2473 base_hashes = "" |
2471 for file, info in files.iteritems(): | 2474 for file, info in files.iteritems(): |
2472 if not info[0] is None: | 2475 if not info[0] is None: |
2473 checksum = md5(info[0]).hexdigest() | 2476 checksum = md5(info[0]).hexdigest() |
2474 if base_hashes: | 2477 if base_hashes: |
2475 base_hashes += "|" | 2478 base_hashes += "|" |
2476 base_hashes += checksum + ":" + file | 2479 base_hashes += checksum + ":" + file |
2477 form_fields.append(("base_hashes", base_hashes)) | 2480 form_fields.append(("base_hashes", base_hashes)) |
2478 if options.private: | 2481 if options.private: |
2479 if options.issue: | 2482 if options.issue: |
2480 print "Warning: Private flag ignored when updating an existing issue." | 2483 print("Warning: Private flag ignored when updating an existing issue.") |
2481 else: | 2484 else: |
2482 form_fields.append(("private", "1")) | 2485 form_fields.append(("private", "1")) |
2483 if options.send_patch: | 2486 if options.send_patch: |
2484 options.send_mail = True | 2487 options.send_mail = True |
2485 if not options.download_base: | 2488 if not options.download_base: |
2486 form_fields.append(("content_upload", "1")) | 2489 form_fields.append(("content_upload", "1")) |
2487 if len(data) > MAX_UPLOAD_SIZE: | 2490 if len(data) > MAX_UPLOAD_SIZE: |
2488 print "Patch is large, so uploading file patches separately." | 2491 print("Patch is large, so uploading file patches separately.") |
2489 uploaded_diff_file = [] | 2492 uploaded_diff_file = [] |
2490 form_fields.append(("separate_patches", "1")) | 2493 form_fields.append(("separate_patches", "1")) |
2491 else: | 2494 else: |
2492 uploaded_diff_file = [("data", "data.diff", data)] | 2495 uploaded_diff_file = [("data", "data.diff", data)] |
2493 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) | 2496 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) |
2494 response_body = rpc_server.Send("/upload", body, content_type=ctype) | 2497 response_body = rpc_server.Send("/upload", body, content_type=ctype) |
2495 issue, patchset = None, None | 2498 issue, patchset = None, None |
2496 if not options.download_base or not uploaded_diff_file: | 2499 if not options.download_base or not uploaded_diff_file: |
2497 lines = response_body.splitlines() | 2500 lines = response_body.splitlines() |
2498 if len(lines) >= 2: | 2501 if len(lines) >= 2: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2537 try: | 2540 try: |
2538 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" | 2541 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" |
2539 "%(lineno)s %(message)s ")) | 2542 "%(lineno)s %(message)s ")) |
2540 os.environ['LC_ALL'] = 'C' | 2543 os.environ['LC_ALL'] = 'C' |
2541 RealMain(sys.argv) | 2544 RealMain(sys.argv) |
2542 except KeyboardInterrupt: | 2545 except KeyboardInterrupt: |
2543 print | 2546 print |
2544 StatusUpdate("Interrupted.") | 2547 StatusUpdate("Interrupted.") |
2545 sys.exit(1) | 2548 sys.exit(1) |
2546 except auth.AuthenticationError as e: | 2549 except auth.AuthenticationError as e: |
2547 print >> sys.stderr, e | 2550 print(e, file=sys.stderr) |
2548 sys.exit(1) | 2551 sys.exit(1) |
2549 | 2552 |
2550 | 2553 |
2551 if __name__ == "__main__": | 2554 if __name__ == "__main__": |
2552 main() | 2555 main() |
OLD | NEW |