| OLD | NEW |
| (Empty) |
| 1 # -*- coding: utf-8 -*- | |
| 2 # Copyright 2011 Google Inc. All Rights Reserved. | |
| 3 # | |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); | |
| 5 # you may not use this file except in compliance with the License. | |
| 6 # You may obtain a copy of the License at | |
| 7 # | |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 # | |
| 10 # Unless required by applicable law or agreed to in writing, software | |
| 11 # distributed under the License is distributed on an "AS IS" BASIS, | |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 13 # See the License for the specific language governing permissions and | |
| 14 # limitations under the License. | |
| 15 """Implementation of gsutil version command.""" | |
| 16 | |
| 17 from __future__ import absolute_import | |
| 18 | |
| 19 from hashlib import md5 | |
| 20 import os | |
| 21 import platform | |
| 22 import re | |
| 23 import sys | |
| 24 | |
| 25 import boto | |
| 26 import crcmod | |
| 27 import gslib | |
| 28 from gslib.command import Command | |
| 29 from gslib.util import GetConfigFilePath | |
| 30 from gslib.util import MultiprocessingIsAvailable | |
| 31 from gslib.util import UsingCrcmodExtension | |
| 32 | |
| 33 | |
| 34 _SYNOPSIS = """ | |
| 35 gsutil version | |
| 36 """ | |
| 37 | |
| 38 _DETAILED_HELP_TEXT = (""" | |
| 39 <B>SYNOPSIS</B> | |
| 40 """ + _SYNOPSIS + """ | |
| 41 | |
| 42 | |
| 43 <B>DESCRIPTION</B> | |
| 44 Prints information about the version of gsutil. | |
| 45 | |
| 46 <B>OPTIONS</B> | |
| 47 -l Prints additional information, such as the version of Python | |
| 48 being used, the version of the Boto library, a checksum of the | |
| 49 code, the path to gsutil, and the path to gsutil's configuration | |
| 50 file. | |
| 51 """) | |
| 52 | |
| 53 | |
| 54 class VersionCommand(Command): | |
| 55 """Implementation of gsutil version command.""" | |
| 56 | |
| 57 # Command specification. See base class for documentation. | |
| 58 command_spec = Command.CreateCommandSpec( | |
| 59 'version', | |
| 60 command_name_aliases=['ver'], | |
| 61 usage_synopsis=_SYNOPSIS, | |
| 62 min_args=0, | |
| 63 max_args=0, | |
| 64 supported_sub_args='l', | |
| 65 file_url_ok=False, | |
| 66 provider_url_ok=False, | |
| 67 urls_start_arg=0, | |
| 68 ) | |
| 69 # Help specification. See help_provider.py for documentation. | |
| 70 help_spec = Command.HelpSpec( | |
| 71 help_name='version', | |
| 72 help_name_aliases=['ver'], | |
| 73 help_type='command_help', | |
| 74 help_one_line_summary='Print version info about gsutil', | |
| 75 help_text=_DETAILED_HELP_TEXT, | |
| 76 subcommand_help_text={}, | |
| 77 ) | |
| 78 | |
| 79 def RunCommand(self): | |
| 80 """Command entry point for the version command.""" | |
| 81 long_form = False | |
| 82 if self.sub_opts: | |
| 83 for o, _ in self.sub_opts: | |
| 84 if o == '-l': | |
| 85 long_form = True | |
| 86 | |
| 87 config_path = GetConfigFilePath() | |
| 88 | |
| 89 shipped_checksum = gslib.CHECKSUM | |
| 90 try: | |
| 91 cur_checksum = self._ComputeCodeChecksum() | |
| 92 except IOError: | |
| 93 cur_checksum = 'MISSING FILES' | |
| 94 if shipped_checksum == cur_checksum: | |
| 95 checksum_ok_str = 'OK' | |
| 96 else: | |
| 97 checksum_ok_str = '!= %s' % shipped_checksum | |
| 98 | |
| 99 sys.stdout.write('gsutil version: %s\n' % gslib.VERSION) | |
| 100 | |
| 101 if long_form: | |
| 102 | |
| 103 long_form_output = ( | |
| 104 'checksum: {checksum} ({checksum_ok})\n' | |
| 105 'boto version: {boto_version}\n' | |
| 106 'python version: {python_version}\n' | |
| 107 'OS: {os_version}\n' | |
| 108 'multiprocessing available: {multiprocessing_available}\n' | |
| 109 'using cloud sdk: {cloud_sdk}\n' | |
| 110 'config path: {config_path}\n' | |
| 111 'gsutil path: {gsutil_path}\n' | |
| 112 'compiled crcmod: {compiled_crcmod}\n' | |
| 113 'installed via package manager: {is_package_install}\n' | |
| 114 'editable install: {is_editable_install}\n' | |
| 115 ) | |
| 116 | |
| 117 sys.stdout.write(long_form_output.format( | |
| 118 checksum=cur_checksum, | |
| 119 checksum_ok=checksum_ok_str, | |
| 120 boto_version=boto.__version__, | |
| 121 python_version=sys.version.replace('\n', ''), | |
| 122 os_version='%s %s' % (platform.system(), platform.release()), | |
| 123 multiprocessing_available=MultiprocessingIsAvailable()[0], | |
| 124 cloud_sdk=(os.environ.get('CLOUDSDK_WRAPPER') == '1'), | |
| 125 config_path=config_path, | |
| 126 gsutil_path=gslib.GSUTIL_PATH, | |
| 127 compiled_crcmod=UsingCrcmodExtension(crcmod), | |
| 128 is_package_install=gslib.IS_PACKAGE_INSTALL, | |
| 129 is_editable_install=gslib.IS_EDITABLE_INSTALL, | |
| 130 )) | |
| 131 | |
| 132 return 0 | |
| 133 | |
| 134 def _ComputeCodeChecksum(self): | |
| 135 """Computes a checksum of gsutil code. | |
| 136 | |
| 137 This checksum can be used to determine if users locally modified | |
| 138 gsutil when requesting support. (It's fine for users to make local mods, | |
| 139 but when users ask for support we ask them to run a stock version of | |
| 140 gsutil so we can reduce possible variables.) | |
| 141 | |
| 142 Returns: | |
| 143 MD5 checksum of gsutil code. | |
| 144 """ | |
| 145 if gslib.IS_PACKAGE_INSTALL: | |
| 146 return 'PACKAGED_GSUTIL_INSTALLS_DO_NOT_HAVE_CHECKSUMS' | |
| 147 m = md5() | |
| 148 # Checksum gsutil and all .py files under gslib directory. | |
| 149 files_to_checksum = [gslib.GSUTIL_PATH] | |
| 150 for root, _, files in os.walk(gslib.GSLIB_DIR): | |
| 151 for filepath in files: | |
| 152 if filepath.endswith('.py'): | |
| 153 files_to_checksum.append(os.path.join(root, filepath)) | |
| 154 # Sort to ensure consistent checksum build, no matter how os.walk | |
| 155 # orders the list. | |
| 156 for filepath in sorted(files_to_checksum): | |
| 157 f = open(filepath, 'r') | |
| 158 content = f.read() | |
| 159 content = re.sub(r'(\r\n|\r|\n)', '\n', content) | |
| 160 m.update(content) | |
| 161 f.close() | |
| 162 return m.hexdigest() | |
| OLD | NEW |