def RunCommand()

in gslib/commands/update.py [0:0]


  def RunCommand(self):
    """Command entry point for the update command."""

    if gslib.IS_PACKAGE_INSTALL:
      raise CommandException(
          'The update command is only available for gsutil installed from a '
          'tarball. If you installed gsutil via another method, use the same '
          'method to update it.')

    if system_util.InvokedViaCloudSdk():
      raise CommandException(
          'The update command is disabled for Cloud SDK installs. Please run '
          '"gcloud components update" to update it. Note: the Cloud SDK '
          'incorporates updates to the underlying tools approximately every 2 '
          'weeks, so if you are attempting to update to a recently created '
          'release / pre-release of gsutil it may not yet be available via '
          'the Cloud SDK.')

    https_validate_certificates = CERTIFICATE_VALIDATION_ENABLED
    if not https_validate_certificates:
      raise CommandException(
          'Your boto configuration has https_validate_certificates = False.\n'
          'The update command cannot be run this way, for security reasons.')

    DisallowUpdateIfDataInGsutilDir()

    force_update = False
    no_prompt = False
    if self.sub_opts:
      for o, unused_a in self.sub_opts:
        if o == '-f':
          force_update = True
        if o == '-n':
          no_prompt = True

    dirs_to_remove = []
    tmp_dir = tempfile.mkdtemp()
    dirs_to_remove.append(tmp_dir)
    old_cwd = os.getcwd()
    os.chdir(tmp_dir)

    if not no_prompt:
      self.logger.info('Checking for software update...')
    if self.args:
      update_from_url_str = self.args[0]
      if not update_from_url_str.endswith('.tar.gz'):
        raise CommandException(
            'The update command only works with tar.gz files.')
      for i, result in enumerate(self.WildcardIterator(update_from_url_str)):
        if i > 0:
          raise CommandException(
              'Invalid update URL. Must name a single .tar.gz file.')
        storage_url = result.storage_url
        if storage_url.IsFileUrl() and not storage_url.IsDirectory():
          if not force_update:
            raise CommandException(
                ('"update" command does not support "file://" URLs without the '
                 '-f option.'))
        elif not (storage_url.IsCloudUrl() and storage_url.IsObject()):
          raise CommandException(
              'Invalid update object URL. Must name a single .tar.gz file.')
    else:
      update_from_url_str = GsutilPubTarball()

    # Try to retrieve version info from tarball metadata; failing that; download
    # the tarball and extract the VERSION file. The version lookup will fail
    # when running the update system test, because it retrieves the tarball from
    # a temp file rather than a cloud URL (files lack the version metadata).
    tarball_version = LookUpGsutilVersion(self.gsutil_api, update_from_url_str)
    if tarball_version:
      tf = None
    else:
      tf = self._FetchAndOpenGsutilTarball(update_from_url_str)
      tf.extractall()
      with open(os.path.join('gsutil', 'VERSION'), 'r') as ver_file:
        tarball_version = ver_file.read().strip()

    if not force_update and gslib.VERSION == tarball_version:
      self._CleanUpUpdateCommand(tf, dirs_to_remove, old_cwd)
      if self.args:
        raise CommandException('You already have %s installed.' %
                               update_from_url_str,
                               informational=True)
      else:
        raise CommandException(
            'You already have the latest gsutil release '
            'installed.',
            informational=True)

    if not no_prompt:
      CheckAndMaybePromptForAnalyticsEnabling()
      (_, major) = CompareVersions(tarball_version, gslib.VERSION)
      if major:
        print(('\n'.join(
            textwrap.wrap(
                'This command will update to the "%s" version of gsutil at %s. '
                'NOTE: This a major new version, so it is strongly recommended '
                'that you review the release note details at %s before updating to '
                'this version, especially if you use gsutil in scripts.' %
                (tarball_version, gslib.GSUTIL_DIR, RELEASE_NOTES_URL)))))
      else:
        print(('This command will update to the "%s" version of\ngsutil at %s' %
               (tarball_version, gslib.GSUTIL_DIR)))
    self._ExplainIfSudoNeeded(tf, dirs_to_remove, old_cwd)

    if no_prompt:
      answer = 'y'
    else:
      answer = input('Proceed? [y/N] ')
    if not answer or answer.lower()[0] != 'y':
      self._CleanUpUpdateCommand(tf, dirs_to_remove, old_cwd)
      raise CommandException('Not running update.', informational=True)

    if not tf:
      tf = self._FetchAndOpenGsutilTarball(update_from_url_str)

    # Ignore keyboard interrupts during the update to reduce the chance someone
    # hitting ^C leaves gsutil in a broken state.
    RegisterSignalHandler(signal.SIGINT, signal.SIG_IGN)

    # gslib.GSUTIL_DIR lists the path where the code should end up (like
    # /usr/local/gsutil), which is one level down from the relative path in the
    # tarball (since the latter creates files in ./gsutil). So, we need to
    # extract at the parent directory level.
    gsutil_bin_parent_dir = os.path.normpath(
        os.path.join(gslib.GSUTIL_DIR, '..'))

    # Extract tarball to a temporary directory in a sibling to GSUTIL_DIR.
    old_dir = tempfile.mkdtemp(dir=gsutil_bin_parent_dir)
    new_dir = tempfile.mkdtemp(dir=gsutil_bin_parent_dir)
    dirs_to_remove.append(old_dir)
    dirs_to_remove.append(new_dir)
    self._EnsureDirsSafeForUpdate(dirs_to_remove)
    try:
      tf.extractall(path=new_dir)
    except Exception as e:
      self._CleanUpUpdateCommand(tf, dirs_to_remove, old_cwd)
      raise CommandException('Update failed: %s.' % e)

    # For enterprise mode (shared/central) installation, users with
    # different user/group than the installation user/group must be
    # able to run gsutil so we need to do some permissions adjustments
    # here. Since enterprise mode is not not supported for Windows
    # users, we can skip this step when running on Windows, which
    # avoids the problem that Windows has no find or xargs command.
    if not system_util.IS_WINDOWS:
      # Make all files and dirs in updated area owner-RW and world-R, and make
      # all directories owner-RWX and world-RX.
      for dirname, subdirs, filenames in os.walk(new_dir):
        for filename in filenames:
          fd = os.open(os.path.join(dirname, filename), os.O_RDONLY)
          os.fchmod(fd,
                    stat.S_IWRITE | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
          os.close(fd)
        for subdir in subdirs:
          fd = os.open(os.path.join(dirname, subdir), os.O_RDONLY)
          os.fchmod(
              fd, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH | stat.S_IRGRP |
              stat.S_IROTH)
          os.close(fd)

      # Make main gsutil script owner-RWX and world-RX.
      fd = os.open(os.path.join(new_dir, 'gsutil', 'gsutil'), os.O_RDONLY)
      os.fchmod(
          fd, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH |
          stat.S_IXOTH)
      os.close(fd)

    # Move old installation aside and new into place.
    os.rename(gslib.GSUTIL_DIR, os.path.join(old_dir, 'old'))
    os.rename(os.path.join(new_dir, 'gsutil'), gslib.GSUTIL_DIR)
    self._CleanUpUpdateCommand(tf, dirs_to_remove, old_cwd)
    RegisterSignalHandler(signal.SIGINT, signal.SIG_DFL)
    self.logger.info('Update complete.')
    return 0