def Update(self, update_seed=None, allow_no_backup=False, throw_if_unattended=False): """Performs an update of the given components. If no components are provided, it will attempt to update everything you have installed. Args: update_seed: list of str, A list of component ids to update. allow_no_backup: bool, True if we want to allow the updater to run without creating a backup. This lets us be in the root directory of the SDK and still do an update. It is more fragile if there is a failure, so we only do it if necessary. throw_if_unattended: bool, True to throw an exception on prompts when not running in interactive mode. Returns: bool, True if the update succeeded (or there was nothing to do, False if if was cancelled by the user. Raises: InvalidComponentError: If any of the given component ids do not exist. """ md5dict1 = self._HashRcfiles(_SHELL_RCFILES) self._EnsureNotDisabled() old_release_notes = release_notes.GetReleaseNotes(self.__sdk_root) try: install_state, diff = self._GetStateAndDiff( command_path='components.update') except snapshots.IncompatibleSchemaVersionError as e: return self._ReinstallOnError(e) if update_seed: invalid_seeds = diff.InvalidUpdateSeeds(update_seed) if invalid_seeds: if os.environ.get('CLOUDSDK_REINSTALL_COMPONENTS'): # We are doing a reinstall. Ignore any components that no longer # exist. update_seed = set(update_seed) - invalid_seeds else: ignored = set(_IGNORED_MISSING_COMPONENTS) deprecated = invalid_seeds & ignored for item in deprecated: log.warning('Component [%s] no longer exists.', item) additional_msg = _IGNORED_MISSING_COMPONENTS.get(item) if additional_msg: log.warning(additional_msg) invalid_seeds -= ignored if invalid_seeds: raise InvalidComponentError( 'The following components are unknown [{invalid_seeds}]' .format(invalid_seeds=', '.join(invalid_seeds))) update_seed = set(update_seed) - deprecated else: update_seed = diff.current.components.keys() to_remove = diff.ToRemove(update_seed) to_install = diff.ToInstall(update_seed) self.__Write(log.status) if not to_remove and not to_install: self.__Write(log.status, 'All components are up to date.') with install_state.LastUpdateCheck() as update_check: update_check.SetFromSnapshot( diff.latest, force=True, platform_filter=self.__platform_filter) return True disable_backup = self._ShouldDoFastUpdate( allow_no_backup=allow_no_backup) self._PrintPendingAction( diff.DetailsForCurrent(to_remove - to_install), 'removed') self._PrintPendingAction(diff.DetailsForLatest(to_remove & to_install), 'updated') self._PrintPendingAction(diff.DetailsForLatest(to_install - to_remove), 'installed') self.__Write(log.status) if diff.latest.sdk_definition.release_notes_url: self.__Write( log.status, 'For the latest full release notes, please visit:\n {0}'. format(diff.latest.sdk_definition.release_notes_url)) message = self._GetDontCancelMessage(disable_backup) if not console_io.PromptContinue( message=message, throw_if_unattended=throw_if_unattended): return False components_to_install = diff.DetailsForLatest(to_install) components_to_remove = diff.DetailsForCurrent(to_remove) for c in components_to_install: metrics.Installs(c.id, c.version.version_string) if disable_backup: with execution_utils.UninterruptibleSection(stream=log.status): self.__Write(log.status, 'Performing in place update...\n') self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', install_state.Uninstall) self._UpdateWithProgressBar( components_to_install, 'Installing', self._InstallFunction(install_state, diff)) else: with console_io.ProgressBar(label='Creating update staging area', stream=log.status) as pb: staging_state = install_state.CloneToStaging(pb.SetProgress) self.__Write(log.status) self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', staging_state.Uninstall) self._UpdateWithProgressBar( components_to_install, 'Installing', self._InstallFunction(staging_state, diff)) self.__Write(log.status) self.__Write(log.status, 'Creating backup and activating new installation...') install_state.ReplaceWith(staging_state) with install_state.LastUpdateCheck() as update_check: update_check.SetFromSnapshot( diff.latest, force=True, platform_filter=self.__platform_filter) md5dict2 = self._HashRcfiles(_SHELL_RCFILES) if md5dict1 != md5dict2: self.__Write( log.status, '\nStart a new shell for the changes to take effect.\n') self.__Write(log.status, '\nUpdate done!\n') if self.__warn: bad_commands = self.FindAllOldToolsOnPath() if bad_commands and not os.environ.get( 'CLOUDSDK_REINSTALL_COMPONENTS'): log.warning("""\ There are older versions of Google Cloud Platform tools on your system PATH. Please remove the following to avoid accidentally invoking these old tools: {0} """.format('\n'.join(bad_commands))) new_release_notes = release_notes.GetReleaseNotes(self.__sdk_root) changed_entries = release_notes.ChangesBetween(old_release_notes, new_release_notes) if changed_entries: log.status.Print( 'The following release notes are new in this upgrade. ' 'Please read carefully for information about new ' 'features, breaking changes, and bugs fixed:\n') log.status.Print('\n\n'.join(changed_entries)) return True
def Remove(self, ids, allow_no_backup=False): """Uninstalls the given components. Args: ids: list of str, The component ids to uninstall. allow_no_backup: bool, True if we want to allow the updater to run without creating a backup. This lets us be in the root directory of the SDK and still do an update. It is more fragile if there is a failure, so we only do it if necessary. Raises: InvalidComponentError: If any of the given component ids are not installed or cannot be removed. """ self._EnsureNotDisabled() if not ids: return install_state = self._GetInstallState() snapshot = install_state.Snapshot() id_set = set(ids) not_installed = id_set - set(snapshot.components.keys()) if not_installed: raise InvalidComponentError( 'The following components are not currently installed [{components}]' .format(components=', '.join(not_installed))) required_components = set( c_id for c_id, component in snapshot.components.iteritems() if c_id in id_set and component.is_required) if required_components: raise InvalidComponentError( ('The following components are required and cannot be removed ' '[{components}]').format( components=', '.join(required_components))) to_remove = snapshot.ConsumerClosureForComponents(ids) if not to_remove: self.__Write(log.status, 'No components to remove.\n') return disable_backup = self._ShouldDoFastUpdate( allow_no_backup=allow_no_backup) components_to_remove = sorted(snapshot.ComponentsFromIds(to_remove), key=lambda c: c.details.display_name) self._PrintPendingAction(components_to_remove, 'removed') self.__Write(log.status) message = self._GetDontCancelMessage(disable_backup) if not console_io.PromptContinue(message): return if disable_backup: with execution_utils.UninterruptibleSection(stream=log.status): self.__Write(log.status, 'Performing in place update...\n') self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', install_state.Uninstall) else: with console_io.ProgressBar(label='Creating update staging area', stream=log.status) as pb: staging_state = install_state.CloneToStaging(pb.SetProgress) self.__Write(log.status) self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', staging_state.Uninstall) self.__Write(log.status) self.__Write(log.status, 'Creating backup and activating new installation...') install_state.ReplaceWith(staging_state) self.__Write(log.status, '\nUninstall done!\n')
def Update(self, update_seed=None, allow_no_backup=False, throw_if_unattended=False): """Performs an update of the given components. If no components are provided, it will attempt to update everything you have installed. Args: update_seed: list of str, A list of component ids to update. allow_no_backup: bool, True if we want to allow the updater to run without creating a backup. This lets us be in the root directory of the SDK and still do an update. It is more fragile if there is a failure, so we only do it if necessary. throw_if_unattended: bool, True to throw an exception on prompts when not running in interactive mode. Returns: bool, True if the update succeeded (or there was nothing to do, False if if was cancelled by the user. Raises: InvalidComponentError: If any of the given component ids do not exist. """ self._EnsureNotDisabled() try: install_state, diff = self._GetStateAndDiff() except snapshots.IncompatibleSchemaVersionError as e: return self._ReinstallOnError(e) if update_seed: invalid_seeds = diff.InvalidUpdateSeeds(update_seed) if invalid_seeds: if os.environ.get('CLOUDSDK_REINSTALL_COMPONENTS'): # We are doing a reinstall. Ignore any components that no longer # exist. update_seed = set(update_seed) - invalid_seeds else: raise InvalidComponentError( 'The following components are unknown [{invalid_seeds}]' .format(invalid_seeds=', '.join(invalid_seeds))) else: update_seed = diff.current.components.keys() to_remove = diff.ToRemove(update_seed) to_install = diff.ToInstall(update_seed) self.__Write(log.status) if not to_remove and not to_install: self.__Write(log.status, 'All components are up to date.') with install_state.LastUpdateCheck() as update_check: update_check.SetFromSnapshot(diff.latest, force=True) return True disable_backup = self._ShouldDoFastUpdate( allow_no_backup=allow_no_backup) self._PrintPendingAction( diff.DetailsForCurrent(to_remove - to_install), 'removed') self._PrintPendingAction(diff.DetailsForLatest(to_remove & to_install), 'updated') self._PrintPendingAction(diff.DetailsForLatest(to_install - to_remove), 'installed') self.__Write(log.status) message = self._GetDontCancelMessage(disable_backup) if not console_io.PromptContinue( message=message, throw_if_unattended=throw_if_unattended): return False components_to_install = diff.DetailsForLatest(to_install) components_to_remove = diff.DetailsForCurrent(to_remove) for c in components_to_install: metrics.Installs(c.id, c.version.version_string) if disable_backup: with execution_utils.UninterruptibleSection(): self.__Write(log.status, 'Performing in place update...\n') self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', install_state.Uninstall) self._UpdateWithProgressBar( components_to_install, 'Installing', self._InstallFunction(install_state, diff)) else: with console_io.ProgressBar(label='Creating update staging area', stream=log.status) as pb: staging_state = install_state.CloneToStaging(pb.SetProgress) self.__Write(log.status) self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', staging_state.Uninstall) self._UpdateWithProgressBar( components_to_install, 'Installing', self._InstallFunction(staging_state, diff)) self.__Write(log.status) self.__Write(log.status, 'Creating backup and activating new installation...') install_state.ReplaceWith(staging_state) with install_state.LastUpdateCheck() as update_check: update_check.SetFromSnapshot(diff.latest, force=True) self.__Write(log.status, '\nUpdate done!\n') if self.__warn: bad_commands = self.FindAllOldToolsOnPath() if bad_commands and not os.environ.get( 'CLOUDSDK_REINSTALL_COMPONENTS'): log.warning("""\ There are older versions of Google Cloud Platform tools on your system PATH. Please remove the following to avoid accidentally invoking these old tools: {0} """.format('\n'.join(bad_commands))) return True