def Display(self): """The default display method.""" if not log.IsUserOutputEnabled(): log.info('Display disabled.') # NOTICE: Do not consume resources here. Some commands use this case to # access the results of Run() via the return value of Execute(). However, # to satisfy callers who are only interetsted in silent side effects, # generators/iterators must be converted to a list here. if resource_property.IsListLike(self._resources): return list(self._resources) return self._resources # Initialize the printer. self._InitPrinter() # Add a URI cache update tap if needed. self._AddUriCacheTap() # Add a resource page tap if needed. self._AddPageTap() # Add a resource flatten tap if needed. self._AddFlattenTap() # Add a sort tap if needed. self._AddSortByTap() # Add a resource filter tap if needed. self._AddFilterTap() # Add a resource limit tap if needed. self._AddLimitTap() # Add the URI replace tap if needed. self._AddUriReplaceTap() resources_were_displayed = True if self._printer: # Most command output will end up here. log.info('Display format "%s".', self._format) self._printer.Print(self._resources) resources_were_displayed = self._printer.ResourcesWerePrinted() elif hasattr(self._command, 'Display'): # This will eventually be rare. log.info('Explicit Display.') self._command.Display(self._args, self._resources) # Resource display is done. log.out.flush() # If the default format was used then display the epilog. if not self._args.IsSpecified('format'): self._command.Epilog(resources_were_displayed) return self._resources
def Run(self, cli, args): """Run this command with the given arguments. Args: cli: The cli.CLI object for this command line tool. args: The arguments for this command as a namespace. Returns: The object returned by the module's Run() function. Raises: exceptions.Error: if thrown by the Run() function. exceptions.ExitCodeNoError: if the command is returning with a non-zero exit code. """ def Http(**kwargs): # Possibly override timeout, making sure to leave kwargs[timeout] # undefined (as opposed to None) if args.http_timout is not set. if args.http_timeout: kwargs['timeout'] = args.http_timeout return core_cli.Http(cmd_path=self.dotted_name, trace_token=args.trace_token, log_http=properties.VALUES.core.log_http.GetBool(), **kwargs) tool_context = self._config_hooks.load_context() last_group = None for context_filter in self._config_hooks.context_filters: last_group = context_filter(tool_context, Http, args) command_instance = self._common_type( cli=cli, context=tool_context, group=last_group, http_func=Http, format_string=args.format or 'yaml') if args.format: output_formatter = command_instance.format else: output_formatter = lambda obj: command_instance.Display(args, obj) log.debug('Running %s with %s.', self.dotted_name, args) metrics.Loaded() result = command_instance.Run(args) if log.IsUserOutputEnabled(): output_formatter(result) metrics.Ran() if command_instance.exit_code != 0: raise exceptions.ExitCodeNoError(exit_code=command_instance.exit_code) return result
def RunExecutable(cmd_args, strict_error_checking=True, ignore_ssh_errors=False): """Run the given command, handling errors appropriately. Args: cmd_args: list of str, the arguments (including executable path) to run strict_error_checking: bool, whether a non-zero, non-255 exit code should be considered a failure. ignore_ssh_errors: bool, when true ignore all errors, including the 255 exit code. Returns: int, the return code of the command Raises: CommandError: if the command failed (based on the command exit code and the strict_error_checking flag) """ outfile = SSH_OUTPUT_FILE or os.devnull with open(outfile, 'w') as output_file: if log.IsUserOutputEnabled() and not SSH_OUTPUT_FILE: stdout, stderr = None, None else: stdout, stderr = output_file, output_file if (platforms.OperatingSystem.IsWindows() and not cmd_args[0].endswith('winkeygen.exe')): # TODO(b/25126583): Drop StrictHostKeyChecking=no and 'y'. # PuTTY and friends always prompt on fingerprint mismatch. A 'y' response # adds/updates the fingerprint registry entry and proceeds. The prompt # will appear once for each new/changed host. Redirecting stdin is not a # problem. Even interactive ssh is not a problem because a separate PuTTY # term is used and it ignores the calling process stdin. stdin = subprocess.PIPE else: stdin = None try: proc = subprocess.Popen(cmd_args, stdin=stdin, stdout=stdout, stderr=stderr) if stdin == subprocess.PIPE: # Max one prompt per host and there can't be more hosts than args. proc.communicate('y\n' * len(cmd_args)) returncode = proc.wait() except OSError as e: raise CommandError(cmd_args[0], message=e.strerror) if not ignore_ssh_errors: if ((returncode and strict_error_checking) or returncode == _SSH_ERROR_EXIT_CODE): raise CommandError(cmd_args[0], return_code=returncode) return returncode
def __exit__(self, exc_type, exc_val, exc_tb): if not exc_val: status = 'SUCCESS' elif isinstance(exc_val, console_io.OperationCancelledError): status = 'INTERRUPTED' else: status = 'FAILURE' if log.IsUserOutputEnabled(): self._stream.write(console_io.JsonUXStub( console_io.UXElementType.PROGRESS_TRACKER, message=self._message, status=status) + '\n') return super(_StubProgressTracker, self).__exit__(exc_type, exc_val, exc_tb)
def Run(self, cli, args): """Run this command with the given arguments. Args: cli: The cli.CLI object for this command line tool. args: The arguments for this command as a namespace. Returns: The object returned by the module's Run() function. Raises: exceptions.Error: if thrown by the Run() function. """ def Http(**kwargs): return core_cli.Http(cmd_path=self.dotted_name, trace_token=args.trace_token, log_http=args.log_http, timeout=args.http_timeout, **kwargs) tool_context = self._config_hooks.load_context() last_group = None for context_filter in self._config_hooks.context_filters: last_group = context_filter(tool_context, Http, args) command_instance = self._common_type(cli=cli, context=tool_context, group=last_group, http_func=Http, format_string=args.format or 'yaml') if args.format: output_formatter = command_instance.format else: output_formatter = lambda obj: command_instance.Display(args, obj) log.debug('Running %s with %s.', self.dotted_name, args) metrics.Loaded() result = command_instance.Run(args) if log.IsUserOutputEnabled(): output_formatter(result) metrics.Ran() if command_instance.exit_code != 0: raise exceptions.ExitCodeNoError( exit_code=command_instance.exit_code) return result
def Display(self): """The default display method.""" if not log.IsUserOutputEnabled(): log.info('Display disabled.') # NOTICE: Do not consume resources here. Some commands use this case to # access the results of Run() via the return value of Execute(). return self._resources # Initialize the printer. self._InitPrinter() # Add a URI cache update tap if needed. self._AddUriCacheTap() # Add a resource page tap if needed. self._AddPageTap() # Add a resource flatten tap if needed. self._AddFlattenTap() # Add a resource filter tap if needed. self._AddFilterTap() # Add a resource limit tap if needed. self._AddLimitTap() # Add the URI replace tap if needed. self._AddUriReplaceTap() resources_were_displayed = True if self._printer: # Most command output will end up here. log.info('Display format "%s".', self._format) self._printer.Print(self._resources) resources_were_displayed = self._printer.ResourcesWerePrinted() elif hasattr(self._command, 'Display'): # This will eventually be rare. log.info('Explict Display.') self._command.Display(self._args, self._resources) # Resource display is done. log.out.flush() # If the default format was used then display the epilog. if self._default_format_used: self._command.Epilog(resources_were_displayed) return self._resources
def _RunExecutable(cmd_args, interactive_ssh=False): with open(os.devnull, 'w') as devnull: if log.IsUserOutputEnabled(): stdout, stderr = None, None else: stdout, stderr = devnull, devnull try: subprocess.check_call(cmd_args, stdout=stdout, stderr=stderr) except OSError as e: raise SshLikeCmdFailed(cmd_args[0], message=e.strerror) except subprocess.CalledProcessError as e: # Interactive ssh exits with the exit status of the last command executed. # This is traditionally not interpreted as an error. if not interactive_ssh or e.returncode == 255: raise SshLikeCmdFailed(cmd_args[0], return_code=e.returncode)
def _RunExecutable(cmd_args, strict_error_checking=True): """Run the given command, handling errors appropriately. Args: cmd_args: list of str, the arguments (including executable path) to run strict_error_checking: bool, whether a non-zero, non-255 exit code should be considered a failure. Returns: int, the return code of the command Raises: SshLikeCmdFailed: if the command failed (based on the command exit code and the strict_error_checking flag) """ with open(os.devnull, 'w') as devnull: if log.IsUserOutputEnabled(): stdout, stderr = None, None else: stdout, stderr = devnull, devnull if _IsRunningOnWindows() and not cmd_args[0].endswith('winkeygen.exe'): # TODO(user): b/25126583 will drop StrictHostKeyChecking=no and 'y'. # PuTTY and friends always prompt on fingerprint mismatch. A 'y' response # adds/updates the fingerprint registry entry and proceeds. The prompt # will appear once for each new/changed host. Redirecting stdin is not a # problem. Even interactive ssh is not a problem because a separate PuTTY # term is used and it ignores the calling process stdin. stdin = subprocess.PIPE else: stdin = None try: proc = subprocess.Popen(cmd_args, stdin=stdin, stdout=stdout, stderr=stderr) if stdin == subprocess.PIPE: # Max one prompt per host and there can't be more hosts than args. proc.communicate('y\n' * len(cmd_args)) returncode = proc.wait() except OSError as e: raise SshLikeCmdFailed(cmd_args[0], message=e.strerror) except subprocess.CalledProcessError as e: if strict_error_checking or e.returncode == _SSH_ERROR_EXIT_CODE: raise SshLikeCmdFailed(cmd_args[0], return_code=e.returncode) return e.returncode return returncode
def _RunExecutable(cmd_args, interactive_ssh=False): with open(os.devnull, 'w') as devnull: if log.IsUserOutputEnabled(): stdout, stderr = None, None else: stdout, stderr = devnull, devnull try: subprocess.check_call(cmd_args, stdout=stdout, stderr=stderr) except OSError as e: raise exceptions.ToolException('[{0}] exited with [{1}].'.format( cmd_args[0], e.strerror)) except subprocess.CalledProcessError as e: # Interactive ssh exits with the exit status of the last command executed. # This is traditionally not interpreted as an error. if not interactive_ssh or e.returncode == 255: raise exceptions.ToolException( '[{0}] exited with return code [{1}].'.format( cmd_args[0], e.returncode))
def Display(self): """The default display method.""" if not log.IsUserOutputEnabled(): log.info('Display disabled.') # NOTICE: Do not consume resources here. Some commands use this case to # access the results of Run() via the return value of Execute(). return self._resources # Determine the format. fmt = self._GetFormat() # Add a URI cache update tap if needed. self._AddUriCacheTap() # Add a resource page tap if needed. self._AddPageTap() # Add a resource flatten tap if needed. self._AddFlattenTap() # Add a resource filter tap if needed. self._AddFilterTap() # Add a resource limit tap if needed. self._AddLimitTap() if fmt: # Most command output will end up here. log.info('Display format "%s".', fmt) resource_printer.Print(self._resources, fmt, defaults=self._defaults, out=log.out) elif hasattr(self._command, 'Display'): # This will eventually be rare. log.info('Explict Display.') self._command.Display(self._args, self._resources) # If the default format was used then display the epilog. if self._default_format_used: self._command.Epilog(self._args) return self._resources
def __exit__(self, exc_type, exc_val, exc_tb): if exc_val and isinstance(exc_val, console_io.OperationCancelledError): status_message = 'INTERRUPTED' elif exc_val: status_message = 'FAILURE' elif self.HasWarning(): status_message = 'WARNING' else: status_message = 'SUCCESS' if log.IsUserOutputEnabled(): self._stream.write(console_io.JsonUXStub( console_io.UXElementType.STAGED_PROGRESS_TRACKER, message=self._message, status=status_message, succeeded_stages=self._succeeded_stages, failed_stage=self._failed_stage) + '\n') return super( _StubStagedProgressTracker, self).__exit__(exc_type, exc_val, exc_tb)
def __init__(self, message, stages, success_message, warning_message, failure_message, autotick, tick_delay, interruptable, aborted_message, tracker_id, done_message_callback, console=None): self._stages = collections.OrderedDict() for stage in stages: if stage.key in self._stages: raise ValueError('Duplicate stage key: {}'.format(stage.key)) self._stages[stage.key] = stage self._stream = sys.stderr # TODO(b/111637901): Support detailed message callback when true multiline # support is available. self._message = message self._success_message = success_message self._warning_message = warning_message self._failure_message = failure_message self._aborted_message = aborted_message self._done_message_callback = done_message_callback self._tracker_id = tracker_id if console is None: console = console_attr.GetConsoleAttr() console_width = console.GetTermSize()[0] if not isinstance(console_width, int) or console_width < 0: # This can happen if we're on a pseudo-TTY. Set it to 0 and also # turn off output to prevent hanging. console_width = 0 self._output_enabled = log.IsUserOutputEnabled() and console_width != 0 # Don't bother autoticking if we aren't going to print anything. self.__autotick = autotick and self._output_enabled self._interruptable = interruptable self._tick_delay = tick_delay self._symbols = console.GetProgressTrackerSymbols() self._done = False self._exception_is_uncaught = True self._ticks = 0 self._ticker = None self._running_stages = set() self._completed_stages = [] self._completed_with_warnings_stages = [] self._exit_output_warnings = [] self._lock = threading.Lock()
def Display(self): """The default display method.""" if not log.IsUserOutputEnabled(): log.debug('Display disabled.') # NOTICE: Do not consume resources here. Some commands use this case to # access the results of Run() via the return value of Execute(). return # Determine the format. fmt = self._GetFormat() if fmt: # Most command output will end up here. log.debug('Display format "%s".', fmt) # TODO(gsfowler): b/24267426 if self._resources is not None: resource_printer.Print(self._resources, fmt, out=log.out) else: # This will eventually be rare. log.debug('Explict Display.') self._command.Display(self._args, self._resources)
def __init__(self, message, autotick, detail_message_callback, tick_delay, interruptable, aborted_message): self._stream = sys.stderr if message is None: self._spinner_only = True self._message = '' self._prefix = '' else: self._spinner_only = False self._message = message self._prefix = message + '...' self._detail_message_callback = detail_message_callback self._ticks = 0 self._done = False self._lock = threading.Lock() self._tick_delay = tick_delay self._ticker = None self._output_enabled = log.IsUserOutputEnabled() # Don't bother autoticking if we aren't going to print anything. self.__autotick = autotick and self._output_enabled self._interruptable = interruptable self._aborted_message = aborted_message self._old_signal_handler = None self._symbols = console_attr.GetConsoleAttr().GetProgressTrackerSymbols()