Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

65 lines
2.0KB

  1. from pathlib import PurePath
  2. from typing import Iterable, Union, Optional, Iterator, NoReturn, Sequence, Mapping
  3. from typing_extensions import Protocol
  4. import subprocess
  5. from .util import Pathish
  6. CommandLineArg = Union[str, Pathish, int, float]
  7. CommandLineArg1 = Union[CommandLineArg, Iterable[CommandLineArg]]
  8. CommandLineArg2 = Union[CommandLineArg1, Iterable[CommandLineArg1]]
  9. CommandLineArg3 = Union[CommandLineArg2, Iterable[CommandLineArg2]]
  10. CommandLineArg4 = Union[CommandLineArg3, Iterable[CommandLineArg3]]
  11. class CommandLine(Protocol):
  12. def __iter__(self) -> Iterator[Union['CommandLine', CommandLineArg]]:
  13. pass
  14. # CommandLine = Union[CommandLineArg4, Iterable[CommandLineArg4]]
  15. class ProcessResult(Protocol):
  16. args: Sequence[str]
  17. returncode: int
  18. stdout: bytes
  19. stderr: bytes
  20. def flatten_cmd(cmd: CommandLine) -> Iterable[str]:
  21. if isinstance(cmd, (str, PurePath)):
  22. yield str(cmd)
  23. elif isinstance(cmd, (int, float)):
  24. yield str(cmd)
  25. elif hasattr(cmd, '__iter__'):
  26. each = (flatten_cmd(arg) for arg in cmd) # type: ignore
  27. for item in each:
  28. yield from item
  29. else:
  30. assert False, f'Invalid command line element: {repr(cmd)}'
  31. def run(*cmd: CommandLine,
  32. cwd: Optional[Pathish] = None,
  33. check: bool = False,
  34. env: Optional[Mapping[str, str]] = None,
  35. timeout: Optional[int] = None) -> ProcessResult:
  36. timeout = timeout or 60 * 5
  37. command = list(flatten_cmd(cmd))
  38. res = subprocess.run(command, cwd=cwd, check=False, env=env, timeout=timeout)
  39. if res.returncode and check:
  40. raise_error(res)
  41. return res
  42. def raise_error(proc: ProcessResult) -> NoReturn:
  43. raise subprocess.CalledProcessError(proc.returncode, proc.args, output=proc.stdout, stderr=proc.stderr)
  44. def check_run(*cmd: CommandLine,
  45. cwd: Optional[Pathish] = None,
  46. env: Optional[Mapping[str, str]] = None,
  47. timeout: Optional[int] = None) -> ProcessResult:
  48. return run(cmd, cwd=cwd, check=True, env=env, timeout=timeout)