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