• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17from __future__ import absolute_import
18
19from hashlib import md5
20import os
21import platform
22import re
23import sys
24
25import boto
26import crcmod
27import gslib
28from gslib.command import Command
29from gslib.util import CheckMultiprocessingAvailableAndInit
30from gslib.util import GetConfigFilePath
31from 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
54class 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