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 CheckMultiprocessingAvailableAndInit 30 from gslib.util import GetConfigFilePath 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=( 124 CheckMultiprocessingAvailableAndInit().is_available), 125 cloud_sdk=(os.environ.get('CLOUDSDK_WRAPPER') == '1'), 126 config_path=config_path, 127 gsutil_path=gslib.GSUTIL_PATH, 128 compiled_crcmod=UsingCrcmodExtension(crcmod), 129 is_package_install=gslib.IS_PACKAGE_INSTALL, 130 is_editable_install=gslib.IS_EDITABLE_INSTALL, 131 )) 132 133 return 0 134 135 def _ComputeCodeChecksum(self): 136 """Computes a checksum of gsutil code. 137 138 This checksum can be used to determine if users locally modified 139 gsutil when requesting support. (It's fine for users to make local mods, 140 but when users ask for support we ask them to run a stock version of 141 gsutil so we can reduce possible variables.) 142 143 Returns: 144 MD5 checksum of gsutil code. 145 """ 146 if gslib.IS_PACKAGE_INSTALL: 147 return 'PACKAGED_GSUTIL_INSTALLS_DO_NOT_HAVE_CHECKSUMS' 148 m = md5() 149 # Checksum gsutil and all .py files under gslib directory. 150 files_to_checksum = [gslib.GSUTIL_PATH] 151 for root, _, files in os.walk(gslib.GSLIB_DIR): 152 for filepath in files: 153 if filepath.endswith('.py'): 154 files_to_checksum.append(os.path.join(root, filepath)) 155 # Sort to ensure consistent checksum build, no matter how os.walk 156 # orders the list. 157 for filepath in sorted(files_to_checksum): 158 f = open(filepath, 'r') 159 content = f.read() 160 content = re.sub(r'(\r\n|\r|\n)', '\n', content) 161 m.update(content) 162 f.close() 163 return m.hexdigest() 164