OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 # Copyright 2013 Google Inc. All Rights Reserved. | 3 # Copyright 2013 Google Inc. All Rights Reserved. |
4 # | 4 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # 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. |
7 # You may obtain a copy of the License at | 7 # You may obtain a copy of the License at |
8 # | 8 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 9 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 10 # |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 DEBUG_WARNING = """ | 96 DEBUG_WARNING = """ |
97 ***************************** WARNING ***************************** | 97 ***************************** WARNING ***************************** |
98 *** You are running gsutil with debug output enabled. | 98 *** You are running gsutil with debug output enabled. |
99 *** Be aware that debug output includes authentication credentials. | 99 *** Be aware that debug output includes authentication credentials. |
100 *** Make sure to remove the value of the Authorization header for | 100 *** Make sure to remove the value of the Authorization header for |
101 *** each HTTP request printed to the console prior to posting to | 101 *** each HTTP request printed to the console prior to posting to |
102 *** a public medium such as a forum post or Stack Overflow. | 102 *** a public medium such as a forum post or Stack Overflow. |
103 ***************************** WARNING ***************************** | 103 ***************************** WARNING ***************************** |
104 """.lstrip() | 104 """.lstrip() |
105 | 105 |
| 106 TRACE_WARNING = """ |
| 107 ***************************** WARNING ***************************** |
| 108 *** You are running gsutil with trace output enabled. |
| 109 *** Be aware that trace output includes authentication credentials |
| 110 *** and may include the contents of any files accessed during the trace. |
| 111 ***************************** WARNING ***************************** |
| 112 """.lstrip() |
| 113 |
106 HTTP_WARNING = """ | 114 HTTP_WARNING = """ |
107 ***************************** WARNING ***************************** | 115 ***************************** WARNING ***************************** |
108 *** You are running gsutil with the "https_validate_certificates" config | 116 *** You are running gsutil with the "https_validate_certificates" config |
109 *** variable set to False. This option should always be set to True in | 117 *** variable set to False. This option should always be set to True in |
110 *** production environments to protect against man-in-the-middle attacks, | 118 *** production environments to protect against man-in-the-middle attacks, |
111 *** and leaking of user data. | 119 *** and leaking of user data. |
112 ***************************** WARNING ***************************** | 120 ***************************** WARNING ***************************** |
113 """.lstrip() | 121 """.lstrip() |
114 | 122 |
115 debug = 0 | 123 debug = 0 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 # Any modules used in initializing multiprocessing variables must be | 188 # Any modules used in initializing multiprocessing variables must be |
181 # imported after importing gslib.__main__. | 189 # imported after importing gslib.__main__. |
182 # pylint: disable=redefined-outer-name,g-import-not-at-top | 190 # pylint: disable=redefined-outer-name,g-import-not-at-top |
183 import gslib.boto_translation | 191 import gslib.boto_translation |
184 import gslib.command | 192 import gslib.command |
185 import gslib.util | 193 import gslib.util |
186 from gslib.util import BOTO_IS_SECURE | 194 from gslib.util import BOTO_IS_SECURE |
187 from gslib.util import CERTIFICATE_VALIDATION_ENABLED | 195 from gslib.util import CERTIFICATE_VALIDATION_ENABLED |
188 # pylint: disable=unused-variable | 196 # pylint: disable=unused-variable |
189 from gcs_oauth2_boto_plugin import oauth2_client | 197 from gcs_oauth2_boto_plugin import oauth2_client |
| 198 from apitools.base.py import credentials_lib |
190 # pylint: enable=unused-variable | 199 # pylint: enable=unused-variable |
191 from gslib.util import MultiprocessingIsAvailable | 200 from gslib.util import CheckMultiprocessingAvailableAndInit |
192 if MultiprocessingIsAvailable()[0]: | 201 if CheckMultiprocessingAvailableAndInit().is_available: |
193 # These setup methods must be called, and, on Windows, they can only be | 202 # These setup methods must be called, and, on Windows, they can only be |
194 # called from within an "if __name__ == '__main__':" block. | 203 # called from within an "if __name__ == '__main__':" block. |
195 gslib.util.InitializeMultiprocessingVariables() | |
196 gslib.command.InitializeMultiprocessingVariables() | 204 gslib.command.InitializeMultiprocessingVariables() |
197 gslib.boto_translation.InitializeMultiprocessingVariables() | 205 gslib.boto_translation.InitializeMultiprocessingVariables() |
| 206 else: |
| 207 gslib.command.InitializeThreadingVariables() |
198 | 208 |
199 # This needs to be done after gslib.util.InitializeMultiprocessingVariables(), | 209 # This needs to be done after gslib.util.InitializeMultiprocessingVariables(), |
200 # since otherwise we can't call gslib.util.CreateLock. | 210 # since otherwise we can't call gslib.util.CreateLock. |
201 try: | 211 try: |
202 # pylint: disable=unused-import,g-import-not-at-top | 212 # pylint: disable=unused-import,g-import-not-at-top |
203 import gcs_oauth2_boto_plugin | 213 import gcs_oauth2_boto_plugin |
204 gcs_oauth2_boto_plugin.oauth2_helper.SetFallbackClientIdAndSecret( | 214 gcs_oauth2_boto_plugin.oauth2_helper.SetFallbackClientIdAndSecret( |
205 GSUTIL_CLIENT_ID, GSUTIL_CLIENT_NOTSOSECRET) | 215 GSUTIL_CLIENT_ID, GSUTIL_CLIENT_NOTSOSECRET) |
206 gcs_oauth2_boto_plugin.oauth2_helper.SetLock(CreateLock()) | 216 gcs_oauth2_boto_plugin.oauth2_helper.SetLock(CreateLock()) |
| 217 credentials_lib.SetCredentialsCacheFileLock(CreateLock()) |
207 except ImportError: | 218 except ImportError: |
208 pass | 219 pass |
209 | 220 |
210 global debug | 221 global debug |
211 global test_exception_traces | 222 global test_exception_traces |
212 | 223 |
213 if not (2, 6) <= sys.version_info[:3] < (3,): | 224 if not (2, 6) <= sys.version_info[:3] < (3,): |
214 raise gslib.exception.CommandException( | 225 raise gslib.exception.CommandException( |
215 'gsutil requires python 2.6 or 2.7.') | 226 'gsutil requires python 2.6 or 2.7.') |
216 | 227 |
217 # In gsutil 4.0 and beyond, we don't use the boto library for the JSON | 228 # In gsutil 4.0 and beyond, we don't use the boto library for the JSON |
218 # API. However, we still store gsutil configuration data in the .boto | 229 # API. However, we still store gsutil configuration data in the .boto |
219 # config file for compatibility with previous versions and user convenience. | 230 # config file for compatibility with previous versions and user convenience. |
220 # Many users have a .boto configuration file from previous versions, and it | 231 # Many users have a .boto configuration file from previous versions, and it |
221 # is useful to have all of the configuration for gsutil stored in one place. | 232 # is useful to have all of the configuration for gsutil stored in one place. |
222 command_runner = CommandRunner() | 233 command_runner = CommandRunner() |
223 if not BOTO_IS_SECURE: | 234 if not BOTO_IS_SECURE: |
224 raise CommandException('\n'.join(textwrap.wrap( | 235 raise CommandException('\n'.join(textwrap.wrap( |
225 'Your boto configuration has is_secure = False. Gsutil cannot be ' | 236 'Your boto configuration has is_secure = False. Gsutil cannot be ' |
226 'run this way, for security reasons.'))) | 237 'run this way, for security reasons.'))) |
227 | 238 |
228 headers = {} | 239 headers = {} |
229 parallel_operations = False | 240 parallel_operations = False |
230 quiet = False | 241 quiet = False |
231 version = False | 242 version = False |
232 debug = 0 | 243 debug = 0 |
| 244 trace_token = None |
233 test_exception_traces = False | 245 test_exception_traces = False |
234 | 246 |
235 # If user enters no commands just print the usage info. | 247 # If user enters no commands just print the usage info. |
236 if len(sys.argv) == 1: | 248 if len(sys.argv) == 1: |
237 sys.argv.append('help') | 249 sys.argv.append('help') |
238 | 250 |
239 # Change the default of the 'https_validate_certificates' boto option to | 251 # Change the default of the 'https_validate_certificates' boto option to |
240 # True (it is currently False in boto). | 252 # True (it is currently False in boto). |
241 if not boto.config.has_option('Boto', 'https_validate_certificates'): | 253 if not boto.config.has_option('Boto', 'https_validate_certificates'): |
242 if not boto.config.has_section('Boto'): | 254 if not boto.config.has_section('Boto'): |
243 boto.config.add_section('Boto') | 255 boto.config.add_section('Boto') |
244 boto.config.setbool('Boto', 'https_validate_certificates', True) | 256 boto.config.setbool('Boto', 'https_validate_certificates', True) |
245 | 257 |
246 gslib.util.certs_file_lock = CreateLock() | 258 gslib.util.certs_file_lock = CreateLock() |
247 for signal_num in GetCaughtSignals(): | 259 for signal_num in GetCaughtSignals(): |
248 RegisterSignalHandler(signal_num, _CleanupSignalHandler) | 260 RegisterSignalHandler(signal_num, _CleanupSignalHandler) |
249 GetCertsFile() | 261 GetCertsFile() |
250 | 262 |
251 try: | 263 try: |
252 try: | 264 try: |
253 opts, args = getopt.getopt(sys.argv[1:], 'dDvo:h:mq', | 265 opts, args = getopt.getopt(sys.argv[1:], 'dDvo:h:mq', |
254 ['debug', 'detailedDebug', 'version', 'option', | 266 ['debug', 'detailedDebug', 'version', 'option', |
255 'help', 'header', 'multithreaded', 'quiet', | 267 'help', 'header', 'multithreaded', 'quiet', |
256 'testexceptiontraces']) | 268 'testexceptiontraces', 'trace-token=']) |
257 except getopt.GetoptError as e: | 269 except getopt.GetoptError as e: |
258 _HandleCommandException(gslib.exception.CommandException(e.msg)) | 270 _HandleCommandException(gslib.exception.CommandException(e.msg)) |
259 for o, a in opts: | 271 for o, a in opts: |
260 if o in ('-d', '--debug'): | 272 if o in ('-d', '--debug'): |
261 # Passing debug=2 causes boto to include httplib header output. | 273 # Passing debug=2 causes boto to include httplib header output. |
262 debug = 3 | 274 debug = 3 |
263 elif o in ('-D', '--detailedDebug'): | 275 elif o in ('-D', '--detailedDebug'): |
264 # We use debug level 3 to ask gsutil code to output more detailed | 276 # We use debug level 3 to ask gsutil code to output more detailed |
265 # debug output. This is a bit of a hack since it overloads the same | 277 # debug output. This is a bit of a hack since it overloads the same |
266 # flag that was originally implemented for boto use. And we use -DD | 278 # flag that was originally implemented for boto use. And we use -DD |
267 # to ask for really detailed debugging (i.e., including HTTP payload). | 279 # to ask for really detailed debugging (i.e., including HTTP payload). |
268 if debug == 3: | 280 if debug == 3: |
269 debug = 4 | 281 debug = 4 |
270 else: | 282 else: |
271 debug = 3 | 283 debug = 3 |
272 elif o in ('-?', '--help'): | 284 elif o in ('-?', '--help'): |
273 _OutputUsageAndExit(command_runner) | 285 _OutputUsageAndExit(command_runner) |
274 elif o in ('-h', '--header'): | 286 elif o in ('-h', '--header'): |
275 (hdr_name, _, hdr_val) = a.partition(':') | 287 (hdr_name, _, hdr_val) = a.partition(':') |
276 if not hdr_name: | 288 if not hdr_name: |
277 _OutputUsageAndExit(command_runner) | 289 _OutputUsageAndExit(command_runner) |
278 headers[hdr_name.lower()] = hdr_val | 290 headers[hdr_name.lower()] = hdr_val |
279 elif o in ('-m', '--multithreaded'): | 291 elif o in ('-m', '--multithreaded'): |
280 parallel_operations = True | 292 parallel_operations = True |
281 elif o in ('-q', '--quiet'): | 293 elif o in ('-q', '--quiet'): |
282 quiet = True | 294 quiet = True |
283 elif o in ('-v', '--version'): | 295 elif o in ('-v', '--version'): |
284 version = True | 296 version = True |
| 297 elif o == '--trace-token': |
| 298 trace_token = a |
285 elif o == '--testexceptiontraces': # Hidden flag for integration tests. | 299 elif o == '--testexceptiontraces': # Hidden flag for integration tests. |
286 test_exception_traces = True | 300 test_exception_traces = True |
287 elif o in ('-o', '--option'): | 301 elif o in ('-o', '--option'): |
288 (opt_section_name, _, opt_value) = a.partition('=') | 302 (opt_section_name, _, opt_value) = a.partition('=') |
289 if not opt_section_name: | 303 if not opt_section_name: |
290 _OutputUsageAndExit(command_runner) | 304 _OutputUsageAndExit(command_runner) |
291 (opt_section, _, opt_name) = opt_section_name.partition(':') | 305 (opt_section, _, opt_name) = opt_section_name.partition(':') |
292 if not opt_section or not opt_name: | 306 if not opt_section or not opt_name: |
293 _OutputUsageAndExit(command_runner) | 307 _OutputUsageAndExit(command_runner) |
294 if not boto.config.has_section(opt_section): | 308 if not boto.config.has_section(opt_section): |
295 boto.config.add_section(opt_section) | 309 boto.config.add_section(opt_section) |
296 boto.config.set(opt_section, opt_name, opt_value) | 310 boto.config.set(opt_section, opt_name, opt_value) |
297 httplib2.debuglevel = debug | 311 httplib2.debuglevel = debug |
| 312 if trace_token: |
| 313 sys.stderr.write(TRACE_WARNING) |
298 if debug > 1: | 314 if debug > 1: |
299 sys.stderr.write(DEBUG_WARNING) | 315 sys.stderr.write(DEBUG_WARNING) |
300 if debug >= 2: | 316 if debug >= 2: |
301 _ConfigureLogging(level=logging.DEBUG) | 317 _ConfigureLogging(level=logging.DEBUG) |
302 command_runner.RunNamedCommand('ver', ['-l']) | 318 command_runner.RunNamedCommand('ver', ['-l']) |
303 config_items = [] | 319 config_items = [] |
304 try: | 320 try: |
305 config_items.extend(boto.config.items('Boto')) | 321 config_items.extend(boto.config.items('Boto')) |
306 config_items.extend(boto.config.items('GSUtil')) | 322 config_items.extend(boto.config.items('GSUtil')) |
307 except ConfigParser.NoSectionError: | 323 except ConfigParser.NoSectionError: |
(...skipping 24 matching lines...) Expand all Loading... |
332 else: | 348 else: |
333 command_name = args[0] | 349 command_name = args[0] |
334 | 350 |
335 _CheckAndWarnForProxyDifferences() | 351 _CheckAndWarnForProxyDifferences() |
336 | 352 |
337 if os.environ.get('_ARGCOMPLETE', '0') == '1': | 353 if os.environ.get('_ARGCOMPLETE', '0') == '1': |
338 return _PerformTabCompletion(command_runner) | 354 return _PerformTabCompletion(command_runner) |
339 | 355 |
340 return _RunNamedCommandAndHandleExceptions( | 356 return _RunNamedCommandAndHandleExceptions( |
341 command_runner, command_name, args=args[1:], headers=headers, | 357 command_runner, command_name, args=args[1:], headers=headers, |
342 debug_level=debug, parallel_operations=parallel_operations) | 358 debug_level=debug, trace_token=trace_token, |
| 359 parallel_operations=parallel_operations) |
343 finally: | 360 finally: |
344 _Cleanup() | 361 _Cleanup() |
345 | 362 |
346 | 363 |
347 def _CheckAndWarnForProxyDifferences(): | 364 def _CheckAndWarnForProxyDifferences(): |
348 # If there are both boto config and environment variable config present for | 365 # If there are both boto config and environment variable config present for |
349 # proxies, unset the environment variable and warn if it differs. | 366 # proxies, unset the environment variable and warn if it differs. |
350 boto_port = boto.config.getint('Boto', 'proxy_port', 0) | 367 boto_port = boto.config.getint('Boto', 'proxy_port', 0) |
351 if boto.config.get('Boto', 'proxy', None) or boto_port: | 368 if boto.config.get('Boto', 'proxy', None) or boto_port: |
352 for proxy_env_var in ['http_proxy', 'https_proxy', 'HTTPS_PROXY']: | 369 for proxy_env_var in ['http_proxy', 'https_proxy', 'HTTPS_PROXY']: |
(...skipping 29 matching lines...) Expand all Loading... |
382 'environment variable and boto configuration, but ' | 399 'environment variable and boto configuration, but ' |
383 'configuration differs. boto configuration proxy values will ' | 400 'configuration differs. boto configuration proxy values will ' |
384 'be used. Differences detected:' % proxy_env_var))) | 401 'be used. Differences detected:' % proxy_env_var))) |
385 sys.stderr.write('\n%s\n' % '\n'.join(differing_values)) | 402 sys.stderr.write('\n%s\n' % '\n'.join(differing_values)) |
386 # Regardless of whether the proxy configuration values matched, | 403 # Regardless of whether the proxy configuration values matched, |
387 # delete the environment variable so as not to confuse boto. | 404 # delete the environment variable so as not to confuse boto. |
388 del os.environ[proxy_env_var] | 405 del os.environ[proxy_env_var] |
389 | 406 |
390 | 407 |
391 def _HandleUnknownFailure(e): | 408 def _HandleUnknownFailure(e): |
392 # Called if we fall through all known/handled exceptions. Allows us to | 409 # Called if we fall through all known/handled exceptions. |
393 # print a stacktrace if -D option used. | 410 _OutputAndExit('Failure: %s.' % e) |
394 if debug >= 2: | |
395 stack_trace = traceback.format_exc() | |
396 sys.stderr.write('DEBUG: Exception stack trace:\n %s\n' % | |
397 re.sub('\\n', '\n ', stack_trace)) | |
398 else: | |
399 _OutputAndExit('Failure: %s.' % e) | |
400 | 411 |
401 | 412 |
402 def _HandleCommandException(e): | 413 def _HandleCommandException(e): |
403 if e.informational: | 414 if e.informational: |
404 _OutputAndExit(e.reason) | 415 _OutputAndExit(e.reason) |
405 else: | 416 else: |
406 _OutputAndExit('CommandException: %s' % e.reason) | 417 _OutputAndExit('CommandException: %s' % e.reason) |
407 | 418 |
408 | 419 |
409 # pylint: disable=unused-argument | 420 # pylint: disable=unused-argument |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 elif (e.reason and | 510 elif (e.reason and |
500 (e.reason == 'AccountProblem' or e.reason == 'Account disabled.' or | 511 (e.reason == 'AccountProblem' or e.reason == 'Account disabled.' or |
501 'account for the specified project has been disabled' in e.reason) | 512 'account for the specified project has been disabled' in e.reason) |
502 and ','.join(args).find('gs://') != -1): | 513 and ','.join(args).find('gs://') != -1): |
503 _OutputAndExit('\n'.join(textwrap.wrap( | 514 _OutputAndExit('\n'.join(textwrap.wrap( |
504 _ConstructAccountProblemHelp(e.reason)))) | 515 _ConstructAccountProblemHelp(e.reason)))) |
505 | 516 |
506 | 517 |
507 def _RunNamedCommandAndHandleExceptions(command_runner, command_name, args=None, | 518 def _RunNamedCommandAndHandleExceptions(command_runner, command_name, args=None, |
508 headers=None, debug_level=0, | 519 headers=None, debug_level=0, |
| 520 trace_token=None, |
509 parallel_operations=False): | 521 parallel_operations=False): |
510 """Runs the command with the given command runner and arguments.""" | 522 """Runs the command with the given command runner and arguments.""" |
511 # pylint: disable=g-import-not-at-top | 523 # pylint: disable=g-import-not-at-top |
512 from gslib.util import GetConfigFilePath | 524 from gslib.util import GetConfigFilePath |
513 from gslib.util import IS_WINDOWS | 525 from gslib.util import IS_WINDOWS |
514 from gslib.util import IsRunningInteractively | 526 from gslib.util import IsRunningInteractively |
515 try: | 527 try: |
516 # Catch ^C so we can print a brief message instead of the normal Python | 528 # Catch ^C so we can print a brief message instead of the normal Python |
517 # stack trace. Register as a final signal handler because this handler kills | 529 # stack trace. Register as a final signal handler because this handler kills |
518 # the main gsutil process (so it must run last). | 530 # the main gsutil process (so it must run last). |
519 RegisterSignalHandler(signal.SIGINT, _HandleControlC, is_final_handler=True) | 531 RegisterSignalHandler(signal.SIGINT, _HandleControlC, is_final_handler=True) |
520 # Catch ^\ so we can force a breakpoint in a running gsutil. | 532 # Catch ^\ so we can force a breakpoint in a running gsutil. |
521 if not IS_WINDOWS: | 533 if not IS_WINDOWS: |
522 RegisterSignalHandler(signal.SIGQUIT, _HandleSigQuit) | 534 RegisterSignalHandler(signal.SIGQUIT, _HandleSigQuit) |
523 return command_runner.RunNamedCommand(command_name, args, headers, | 535 return command_runner.RunNamedCommand(command_name, args, headers, |
524 debug_level, parallel_operations) | 536 debug_level, trace_token, |
| 537 parallel_operations) |
525 except AttributeError as e: | 538 except AttributeError as e: |
526 if str(e).find('secret_access_key') != -1: | 539 if str(e).find('secret_access_key') != -1: |
527 _OutputAndExit('Missing credentials for the given URI(s). Does your ' | 540 _OutputAndExit('Missing credentials for the given URI(s). Does your ' |
528 'boto config file contain all needed credentials?') | 541 'boto config file contain all needed credentials?') |
529 else: | 542 else: |
530 _OutputAndExit(str(e)) | 543 _OutputAndExit(str(e)) |
531 except gslib.exception.CommandException as e: | 544 except gslib.exception.CommandException as e: |
532 _HandleCommandException(e) | 545 _HandleCommandException(e) |
533 except getopt.GetoptError as e: | 546 except getopt.GetoptError as e: |
534 _HandleCommandException(gslib.exception.CommandException(e.msg)) | 547 _HandleCommandException(gslib.exception.CommandException(e.msg)) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 ' not found.\nCause: %s' % e) | 635 ' not found.\nCause: %s' % e) |
623 parser = argparse.ArgumentParser(add_help=False) | 636 parser = argparse.ArgumentParser(add_help=False) |
624 subparsers = parser.add_subparsers() | 637 subparsers = parser.add_subparsers() |
625 command_runner.ConfigureCommandArgumentParsers(subparsers) | 638 command_runner.ConfigureCommandArgumentParsers(subparsers) |
626 argcomplete.autocomplete(parser, exit_method=sys.exit) | 639 argcomplete.autocomplete(parser, exit_method=sys.exit) |
627 | 640 |
628 return 0 | 641 return 0 |
629 | 642 |
630 if __name__ == '__main__': | 643 if __name__ == '__main__': |
631 sys.exit(main()) | 644 sys.exit(main()) |
OLD | NEW |