def run_command( cls, cmd: Union[List[str], CommandArgs], show_stdout: bool = True, cwd: Optional[str] = None, on_returncode: 'Literal["raise", "warn", "ignore"]' = "raise", extra_ok_returncodes: Optional[Iterable[int]] = None, command_desc: Optional[str] = None, extra_environ: Optional[Mapping[str, Any]] = None, spinner: Optional[SpinnerInterface] = None, log_failed_cmd: bool = True, stdout_only: bool = False, ) -> str: """ Run a VCS subcommand This is simply a wrapper around call_subprocess that adds the VCS command name, and checks that the VCS is available """ cmd = make_command(cls.name, *cmd) if command_desc is None: command_desc = format_command_args(cmd) try: return call_subprocess( cmd, show_stdout, cwd, on_returncode=on_returncode, extra_ok_returncodes=extra_ok_returncodes, command_desc=command_desc, extra_environ=extra_environ, unset_environ=cls.unset_environ, spinner=spinner, log_failed_cmd=log_failed_cmd, stdout_only=stdout_only, ) except FileNotFoundError: # errno.ENOENT = no such file or directory # In other words, the VCS executable isn't available raise BadCommand(f"Cannot find command {cls.name!r} - do you have " f"{cls.name!r} installed and in your PATH?") except PermissionError: # errno.EACCES = Permission denied # This error occurs, for instance, when the command is installed # only for another user. So, the current user don't have # permission to call the other user command. raise BadCommand( f"No permission to execute {cls.name!r} - install it " f"locally, globally (ask admin), or check your PATH. " f"See possible solutions at " f"https://pip.pypa.io/en/latest/reference/pip_freeze/" f"#fixing-permission-denied.")
def format_command_result( command_args: List[str], command_output: str, ) -> str: """Format command information for logging.""" command_desc = format_command_args(command_args) text = f"Command arguments: {command_desc}\n" if not command_output: text += "Command output: None" elif logger.getEffectiveLevel() > logging.DEBUG: text += "Command output: [use --verbose to show]" else: if not command_output.endswith("\n"): command_output += "\n" text += f"Command output:\n{command_output}" return text
def format_command_result( command_args: List[str], command_output: str, ) -> str: """Format command information for logging.""" command_desc = format_command_args(command_args) text = f'Command arguments: {command_desc}\n' if not command_output: text += 'Command output: None' elif logger.getEffectiveLevel() > logging.DEBUG: text += 'Command output: [use --verbose to show]' else: if not command_output.endswith('\n'): command_output += '\n' text += f'Command output:\n{command_output}{LOG_DIVIDER}' return text
def format_command_result( command_args, # type: List[str] command_output, # type: str ): # type: (...) -> str """Format command information for logging.""" command_desc = format_command_args(command_args) text = 'Command arguments: {}\n'.format(command_desc) if not command_output: text += 'Command output: None' elif logger.getEffectiveLevel() > logging.DEBUG: text += 'Command output: [use --verbose to show]' else: if not command_output.endswith('\n'): command_output += '\n' text += 'Command output:\n{}{}'.format(command_output, LOG_DIVIDER) return text
def call_subprocess( cmd, # type: Union[List[str], CommandArgs] cwd=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] extra_ok_returncodes=None, # type: Optional[Iterable[int]] log_failed_cmd=True, # type: Optional[bool] ): # type: (...) -> Text """ Args: extra_ok_returncodes: an iterable of integer return codes that are acceptable, in addition to 0. Defaults to None, which means []. log_failed_cmd: if false, failed commands are not logged, only raised. """ if extra_ok_returncodes is None: extra_ok_returncodes = [] # log the subprocess output at DEBUG level. log_subprocess = subprocess_logger.debug env = os.environ.copy() if extra_environ: env.update(extra_environ) # Whether the subprocess will be visible in the console. showing_subprocess = True command_desc = format_command_args(cmd) try: proc = subprocess.Popen( # Convert HiddenText objects to the underlying str. reveal_command_args(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, ) if proc.stdin: proc.stdin.close() except Exception as exc: if log_failed_cmd: subprocess_logger.critical( "Error %s while executing command %s", exc, command_desc, ) raise all_output = [] while True: # The "line" value is a unicode string in Python 2. line = None if proc.stdout: line = console_to_str(proc.stdout.readline()) if not line: break line = line.rstrip() all_output.append(line + "\n") # Show the line immediately. log_subprocess(line) try: proc.wait() finally: if proc.stdout: proc.stdout.close() proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes if proc_had_error: if not showing_subprocess and log_failed_cmd: # Then the subprocess streams haven't been logged to the # console yet. msg = make_subprocess_output_error( cmd_args=cmd, cwd=cwd, lines=all_output, exit_status=proc.returncode, ) subprocess_logger.error(msg) exc_msg = ( "Command errored out with exit status {}: {} " "Check the logs for full command output." ).format(proc.returncode, command_desc) raise SubProcessError(exc_msg) return "".join(all_output)
def test_format_command_args(args, expected): actual = format_command_args(args) assert actual == expected
def test_format_command_args(args: CommandArgs, expected: str) -> None: actual = format_command_args(args) assert actual == expected
only raised. """ if extra_ok_returncodes is None: extra_ok_returncodes = [] # log the subprocess output at DEBUG level. log_subprocess = subprocess_logger.debug env = os.environ.copy() if extra_environ: env.update(extra_environ) # Whether the subprocess will be visible in the console. showing_subprocess = True command_desc = format_command_args(cmd) try: proc = subprocess.Popen( # Convert HiddenText objects to the underlying str. reveal_command_args(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd ) if proc.stdin: proc.stdin.close() except Exception as exc: if log_failed_cmd: subprocess_logger.critical( "Error %s while executing command %s", exc, command_desc, )