def testProgressBarLabel(self): pb = console_io.ProgressBar('Test Action', total_ticks=15) pb.Start() self.AssertErrContains('3= Test Action =4\n') self.ClearErr() pb = console_io.ProgressBar('Test Action', total_ticks=14) pb.Start() self.AssertErrContains('3= Test Ac... =4\n')
def _StartMinikubeCluster(cluster_name, vm_driver, debug=False): """Starts a minikube cluster.""" # pylint: disable=broad-except try: if not _IsMinikubeClusterUp(cluster_name): cmd = [ _FindMinikube(), 'start', '-p', cluster_name, '--keep-context', '--interactive=false', '--delete-on-failure', '--install-addons=false', '--output=json', ] if vm_driver: cmd.append('--vm-driver=' + vm_driver) if vm_driver == 'docker': cmd.append('--container-runtime=docker') if debug: cmd.extend(['--alsologtostderr', '-v8']) start_msg = "Starting development environment '%s' ..." % cluster_name with console_io.ProgressBar(start_msg) as progress_bar: for json_obj in run_subprocess.StreamOutputJson( cmd, event_timeout_sec=90, show_stderr=debug): if debug: print('minikube', json_obj) _HandleMinikubeStatusEvent(progress_bar, json_obj) except Exception as e: six.reraise(MinikubeStartError, e, sys.exc_info()[2])
def _UpdateWithProgressBar(self, components, action, action_func, first=False, last=False): """Performs an update on a component while using a progress bar. Args: components: [schemas.Component], The components that are going to be acted on. action: str, The action that is printed for this update. action_func: func, The function to call to actually do the update. It takes a single argument which is the component id. first: bool, True if this is the first stacked ProgressBar group. last: bool, True if this is the last stacked ProgressBar group. """ for index, component in enumerate(components): label = '{action}: {name}'.format( action=action, name=component.details.display_name) with console_io.ProgressBar( label=label, stream=log.status, first=first, last=last and index == len(components) - 1) as pb: action_func(component.id, progress_callback=pb.SetProgress) first = False
def testNoOp(self): properties.VALUES.core.interactive_ux_style.Set( properties.VALUES.core.InteractiveUXStyles.OFF.name) pb = console_io.ProgressBar('Test Action', total_ticks=40) pb.Start() pb.Finish() self.AssertErrEquals('')
def testStub(self): properties.VALUES.core.interactive_ux_style.Set( properties.VALUES.core.InteractiveUXStyles.TESTING.name) pb = console_io.ProgressBar('Test Action', total_ticks=40) pb.Start() pb.Finish() self.AssertErrEquals( '{"ux": "PROGRESS_BAR", "message": "Test Action"}\n')
def Start(self, total_files): self._progress_bar = console_io.ProgressBar( 'Uploading {0} file(s)'.format(total_files)) (self.read_progress, self.write_progress) = (console_io.SplitProgressBar( self._progress_bar.SetProgress, [1, 6])) self._workspace.SetPostCallback(self._UpdateWriteProgress) self.total_files = total_files self._progress_bar.Start()
def testProgressBarScreenReader(self): pb = console_io.ProgressBar('Test Action', screen_reader=True) pb.Start() self.AssertErrEquals('Test Action\n') pb.SetProgress(0.02) self.AssertErrEquals('Test Action\n') pb.SetProgress(0.33) self.AssertErrEquals('Test Action\n33%\n') pb.Finish() self.AssertErrEquals('Test Action\n33%\n100%\n')
def testDefault(self): with console_io.ProgressBar('', total_ticks=10): callbacks = console_io.SplitProgressBar(None, [.1, .4, .5]) self.assertEqual(3, len(callbacks)) self.AssertErrEquals('1==========2\n' '3= =4\n' '5') callbacks[0](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5') callbacks[1](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5') callbacks[2](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5')
def _Update(self, restrict): """Update() helper method. Returns the number of changed help doc files.""" with file_utils.TemporaryDirectory() as temp_dir: pb = console_io.ProgressBar(label='Generating Help Document Files') with TimeIt('Creating walker'): walker = self._generator( self._cli, temp_dir, pb.SetProgress, restrict=restrict) start = time.time() pb.Start() walker.Walk(hidden=True) pb.Finish() elapsed_time = time.time() - start log.info('Generating Help Document Files took {}'.format(elapsed_time)) diff = HelpAccumulator(restrict=restrict) with TimeIt('Diffing'): DirDiff(self._directory, temp_dir, diff) ops = collections.defaultdict(list) changes = 0 with TimeIt('Getting diffs'): for op, path in sorted(diff.GetChanges()): changes += 1 if not self._test or changes < TEST_CHANGES_DISPLAY_MAX: log.status.Print('{0} {1}'.format(op, path)) ops[op].append(path) if self._test: if changes: if changes >= TEST_CHANGES_DISPLAY_MAX: log.status.Print('...') log.status.Print('{0} help text {1} changed'.format( changes, text.Pluralize(changes, 'file'))) return changes with TimeIt('Updating destination files'): for op in ('add', 'edit', 'delete'): for path in ops[op]: dest_path = os.path.join(self._directory, path) if op in ('add', 'edit'): if op == 'add': subdir = os.path.dirname(dest_path) if subdir: file_utils.MakeDir(subdir) temp_path = os.path.join(temp_dir, path) shutil.copyfile(temp_path, dest_path) elif op == 'delete': try: os.remove(dest_path) except OSError: pass return changes
def _AddSourceDirToWorkspace(self, workspace, src_name, target_root): """Add files in the given directory to a workspace. Args: workspace: (source.Workspace) The workspace to add files to. src_name: (string) A directory to snapshot. target_root: (string) Root directory of the target tree in the snapshot. Returns: ([dict], int, int) A 3-tuple containing an array of source contexts, the number of files added to the workspace, and the total size of the files added. """ src_path = os.path.abspath(src_name) source_contexts = [] # Add context for any external repos. try: for s in contexts.CalculateExtendedSourceContexts(src_path): if s not in source_contexts: source_contexts.append(s) except contexts.GenerateSourceContextError: # We don't care if there's no external source context. We can even # snapshot a bunch of local files if necessary. pass # TODO(danielsb) Once "wsync snapshot" is available, use that instead of # explicitly modifying the workspace as we do here. paths = [os.path.relpath(os.path.join(basedir, f), src_path) for basedir, _, files in os.walk(src_path) for f in files] total_files = len(paths) progress_bar = console_io.ProgressBar( 'Uploading {0} files'.format(total_files)) (read_progress, write_progress) = console_io.ProgressBar.SplitProgressBar( progress_bar.SetProgress, [1, 6]) def UpdateProgress(action_count): write_progress((1.0 * action_count) / total_files) workspace.SetPostCallback(UpdateProgress) progress_bar.Start() total_size = 0 file_count = 0 contents = None for path in paths: with open(os.path.join(src_path, path), 'r') as f: contents = f.read() if contents: total_size += len(contents) file_count += 1 read_progress((1.0 * file_count) / total_files) workspace.WriteFile(os.path.join(target_root, path), contents) return (source_contexts, total_files, total_size)
def _AddSourceJarToWorkspace(self, workspace, src_name, target_root): """Add files in the given source jar to a workspace. Args: workspace: (source.Workspace) The workspace to add files to. src_name: (string) A directory tree or source jar to snapshot. target_root: (string) Root directory of the target tree in the snapshot. Returns: ([dict], int, int) A 3-tuple containing an array of source contexts, the number of files added to the workspace, and the total size of the files added. """ source_contexts = [] jar_file = None try: jar_file = zipfile.ZipFile(src_name, 'r') paths = [ zi.filename for zi in jar_file.infolist() if zi.filename.endswith('.java') ] total_files = len(paths) progress_bar = console_io.ProgressBar( 'Uploading {0} files'.format(total_files)) (read_progress, write_progress) = console_io.ProgressBar.SplitProgressBar( progress_bar.SetProgress, [1, 6]) def UpdateProgress(action_count): write_progress((1.0 * action_count) / total_files) workspace.SetPostCallback(UpdateProgress) progress_bar.Start() total_size = 0 file_count = 0 for path in paths: contents = jar_file.read(path) if contents: total_size += len(contents) file_count += 1 read_progress((1.0 * file_count) / total_files) workspace.WriteFile(os.path.join(target_root, path), contents) finally: if jar_file: jar_file.close() return (source_contexts, total_files, total_size)
def _UpdateWithProgressBar(self, components, action, action_func): """Performs an update on a component while using a progress bar. Args: components: [schemas.Component], The components that are going to be acted on. action: str, The action that is printed for this update. action_func: func, The function to call to actually do the update. It takes a single argument which is the component id. """ for component in components: label = '{action}: {name}'.format( action=action, name=component.details.display_name) with console_io.ProgressBar(label=label, stream=log.status) as pb: action_func(component.id, progress_callback=pb.SetProgress)
def testProgressBarAsciiArtStack(self): actions = ['Uninstalling', 'Downloading', 'Installing'] for index, action in enumerate(actions): pb = console_io.ProgressBar(action, total_ticks=40, first=index == 0, last=index == len(actions) - 1) pb.Start() pb.Finish() self.AssertErrEquals('#========================================#\n' '#= Uninstalling =#\n' '#========================================#\n' '#= Downloading =#\n' '#========================================#\n' '#= Installing =#\n' '#========================================#\n')
def DownloadModule(self, module, version, output_dir): """Downloads the given version of the module. Args: module: str, The module to download. version: str, The version of the module to download. output_dir: str, The directory to download the module to. """ rpcserver = self._GetRpcServer() downloader = module_downloader.ModuleDownloader( rpcserver, self.project, module, version) (full_version, file_lines) = downloader.GetFileList() with console_io.ProgressBar(label='Downloading [{0}] files...'.format( len(file_lines)), stream=log.status) as pb: downloader.Download(full_version, file_lines, output_dir, pb.SetProgress)
def testProgressBarAsciiArtStackNonInteractive(self): """Don't make double lines when the char set is ascii.""" self._interactive_mock.return_value = False actions = ['Uninstalling', 'Downloading', 'Installing'] for index, action in enumerate(actions): pb = console_io.ProgressBar(action, total_ticks=40, first=index == 0, last=index == len(actions) - 1) pb.Start() pb.Finish() self.AssertErrEquals('#========================================#\n' '#= Uninstalling =#\n' '#========================================#\n' '#= Downloading =#\n' '#========================================#\n' '#= Installing =#\n' '#========================================#\n')
def testProgressBarAsciiArtSingle(self): pb = console_io.ProgressBar('Test Action', total_ticks=40) self.AssertErrNotContains('|') pb.Start() self.AssertErrContains('#========================================#\n' '#= Test Action =#\n' '#') pb.SetProgress(.25) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#==========') pb.SetProgress(.15) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#==========') pb.SetProgress(.26) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#==========') pb.SetProgress(.49) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#===================') pb.SetProgress(.50) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#====================') pb.SetProgress(1) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#========================================#\n') # Should just stay at 100%. pb.SetProgress(2) self.AssertErrEquals('#========================================#\n' '#= Test Action =#\n' '#========================================#\n')
def testSplit(self): with console_io.ProgressBar('', total_ticks=10) as pb: callbacks = console_io.SplitProgressBar(pb.SetProgress, [.1, .4, .5]) self.assertEqual(3, len(callbacks)) self.AssertErrEquals('1==========2\n' '3= =4\n' '5') callbacks[0](.5) self.AssertErrEquals('1==========2\n' '3= =4\n' '5') callbacks[0](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5=') callbacks[1](.5) self.AssertErrEquals('1==========2\n' '3= =4\n' '5===') callbacks[1](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5=====') callbacks[2](.5) self.AssertErrEquals('1==========2\n' '3= =4\n' '5=======') callbacks[2](1) self.AssertErrEquals('1==========2\n' '3= =4\n' '5==========6\n')
def testProgressBarStackNonInteractive(self): """Don't redraw when non-interactive.""" self._interactive_mock.return_value = False actions = ['Uninstalling', 'Downloading', 'Installing'] for index, action in enumerate(actions): pb = console_io.ProgressBar(action, total_ticks=40, first=index == 0, last=index == len(actions) - 1) pb.Start() pb.Finish() self.AssertErrEquals('1========================================2\n' '3= Uninstalling =4\n' '5========================================6\n' '1========================================2\n' '3= Downloading =4\n' '5========================================6\n' '1========================================2\n' '3= Installing =4\n' '5========================================6\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. """ 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 testProgressBarContextManager(self): with console_io.ProgressBar('Test Action', total_ticks=15): pass self.AssertErrEquals('1===============2\n' '3= Test Action =4\n' '5===============6\n')
def _Update(self, restrict): """Update() helper method. Returns the number of changed help text files.""" with file_utils.TemporaryDirectory() as temp_dir: pb = console_io.ProgressBar(label='Generating Help Docs') walker = walker_util.HelpTextGenerator(self._cli, temp_dir, pb.SetProgress, restrict=restrict) pb.Start() walker.Walk(hidden=True) pb.Finish() diff = HelpTextAccumulator(restrict=restrict) DirDiff(self._help_dir, temp_dir, diff) if diff.invalid_file_count: # Bail out early on invalid content errors. These must be corrected # before proceeding. raise HelpTextUpdateError( '{0} help text {1} with invalid content must be fixed.'. format(diff.invalid_file_count, text.Pluralize(diff.invalid_file_count, 'file'))) ops = {} for op in ['add', 'delete', 'edit']: ops[op] = [] changes = 0 for op, path in sorted(diff.GetChanges()): changes += 1 if not self._test or changes < TEST_CHANGES_DISPLAY_MAX: log.status.Print('{0} {1}'.format(op, path)) ops[op].append(path) if self._test: if changes: if changes >= TEST_CHANGES_DISPLAY_MAX: log.status.Print('...') log.status.Print('{0} help test {1} changed'.format( changes, text.Pluralize(changes, 'file'))) return changes op = 'add' if ops[op]: for path in ops[op]: dest_path = os.path.join(self._help_dir, path) subdir = os.path.dirname(dest_path) if subdir: file_utils.MakeDir(subdir) temp_path = os.path.join(temp_dir, path) shutil.copyfile(temp_path, dest_path) op = 'edit' if ops[op]: for path in ops[op]: dest_path = os.path.join(self._help_dir, path) temp_path = os.path.join(temp_dir, path) shutil.copyfile(temp_path, dest_path) op = 'delete' if ops[op]: for path in ops[op]: dest_path = os.path.join(self._help_dir, path) try: os.remove(dest_path) except OSError: pass return changes
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() try: install_state, diff = self._GetStateAndDiff( command_path='components.update') except snapshots.IncompatibleSchemaVersionError as e: return self._ReinstallOnError(e) original_update_seed = update_seed 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 current_os = platforms.OperatingSystem.Current() if (current_os is platforms.OperatingSystem.WINDOWS and file_utils.IsDirAncestorOf(self.__sdk_root, sys.executable)): # On Windows, you can't use a Python installed within a directory to move # that directory, which means that with a bundled Python, updates will # fail. To get around this, we copy the Python interpreter to a temporary # directory and run it there. # There's no issue that the `.py` files themselves are inside the install # directory, because the Python interpreter loads them into memory and # closes them immediately. RestartCommand(python=_CopyPython(), block=False) sys.exit(0) # If explicitly listing components, you are probably installing and not # doing a full udpate, change the message to be more clear. if original_update_seed: latest_msg = 'Installing components from version: ' else: latest_msg = 'You will be upgraded to version: ' self._PrintVersions(diff, latest_msg=latest_msg) 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) release_notes.PrintReleaseNotesDiff( diff.latest.sdk_definition.release_notes_url, config.INSTALLATION_CONFIG.version, diff.latest.version) 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, first=True, last=not components_to_install) self._UpdateWithProgressBar(components_to_install, 'Installing', self._InstallFunction( install_state, diff), first=not components_to_remove, last=True) else: with console_io.ProgressBar(label='Creating update staging area', stream=log.status, last=False) as pb: staging_state = install_state.CloneToStaging(pb.SetProgress) self._UpdateWithProgressBar(components_to_remove, 'Uninstalling', staging_state.Uninstall, first=False, last=False) self._UpdateWithProgressBar(components_to_install, 'Installing', self._InstallFunction( staging_state, diff), first=False, last=False) with console_io.ProgressBar( label='Creating backup and activating new installation', stream=log.status, first=False) as pb: install_state.ReplaceWith(staging_state, pb.SetProgress) 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))) 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 _DoFreshInstall(self, message, no_update, download_url): """Do a reinstall of what we have based on a fresh download of the SDK. Args: message: str, A message to show to the user before the re-installation. no_update: bool, True to show the message and tell the user they must re-download manually. download_url: The URL the Cloud SDK can be downloaded from. Returns: bool, True if the update succeeded, False if it was cancelled. """ self._EnsureNotDisabled() if os.environ.get('CLOUDSDK_REINSTALL_COMPONENTS'): # We are already reinstalling but got here somehow. Something is very # wrong and we want to avoid the infinite loop. self._RaiseReinstallationFailedError() # Print out an arbitrary message that we wanted to show users for this # update. if message: self.__Write(log.status, msg=message, word_wrap=True) # We can decide that for some reason we just never want to update past this # version of the schema. if no_update: return False answer = console_io.PromptContinue( message= '\nThe component manager must perform a self update before you ' 'can continue. It and all components will be updated to their ' 'latest versions.') if not answer: return False self._ShouldDoFastUpdate(allow_no_backup=False, fast_mode_impossible=True) install_state = self._GetInstallState() try: with console_io.ProgressBar( label='Downloading and extracting updated components', stream=log.status) as pb: staging_state = install_state.CreateStagingFromDownload( download_url, progress_callback=pb.SetProgress) except local_state.Error: log.error('An updated Cloud SDK failed to download') log.debug('Handling re-installation error', exc_info=True) self._RaiseReinstallationFailedError() # shell out to install script installed_component_ids = sorted( install_state.InstalledComponents().keys()) env = dict(os.environ) env['CLOUDSDK_REINSTALL_COMPONENTS'] = ','.join( installed_component_ids) installer_path = os.path.join(staging_state.sdk_root, 'bin', 'bootstrapping', 'install.py') p = subprocess.Popen([sys.executable, '-S', installer_path], env=env) ret_val = p.wait() if ret_val: self._RaiseReinstallationFailedError() self.__Write(log.status, 'Creating backup and activating new installation...') install_state.ReplaceWith(staging_state) self.__Write(log.status, '\nComponents updated!\n') return True