You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

53 lines
1.5KB

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