ominfra 0.0.0.dev223__py3-none-any.whl → 0.0.0.dev225__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ominfra/clouds/aws/journald2aws/driver.py +1 -1
- ominfra/journald/tailer.py +2 -2
- ominfra/manage/commands/subprocess.py +3 -3
- ominfra/manage/remote/spawning.py +2 -2
- ominfra/scripts/journald2aws.py +106 -470
- ominfra/scripts/manage.py +2893 -2824
- ominfra/scripts/supervisor.py +57 -140
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/RECORD +13 -13
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev223.dist-info → ominfra-0.0.0.dev225.dist-info}/top_level.txt +0 -0
@@ -42,7 +42,7 @@ from omlish.lite.check import check
|
|
42
42
|
from omlish.lite.contextmanagers import ExitStacked
|
43
43
|
from omlish.lite.logs import log
|
44
44
|
from omlish.lite.runtime import is_debugger_attached
|
45
|
-
from omlish.os.pidfile import Pidfile
|
45
|
+
from omlish.os.pidfiles.pidfile import Pidfile
|
46
46
|
|
47
47
|
from ....journald.messages import JournalctlMessage # noqa
|
48
48
|
from ....journald.tailer import JournalctlTailerWorker
|
ominfra/journald/tailer.py
CHANGED
@@ -410,8 +410,8 @@ import typing as ta
|
|
410
410
|
from omlish.lite.cached import cached_nullary
|
411
411
|
from omlish.lite.check import check
|
412
412
|
from omlish.lite.logs import log
|
413
|
-
from omlish.subprocesses import subprocess_close
|
414
|
-
from omlish.subprocesses import subprocess_shell_wrap_exec
|
413
|
+
from omlish.subprocesses.utils import subprocess_close
|
414
|
+
from omlish.subprocesses.wrap import subprocess_shell_wrap_exec
|
415
415
|
|
416
416
|
from ..threadworkers import ThreadWorker
|
417
417
|
from .messages import JournalctlMessage # noqa
|
@@ -8,9 +8,9 @@ import typing as ta
|
|
8
8
|
|
9
9
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
10
10
|
from omlish.lite.check import check
|
11
|
-
from omlish.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
|
12
|
-
from omlish.subprocesses import SubprocessChannelOption
|
13
|
-
from omlish.subprocesses import subprocess_maybe_shell_wrap_exec
|
11
|
+
from omlish.subprocesses.base import SUBPROCESS_CHANNEL_OPTION_VALUES
|
12
|
+
from omlish.subprocesses.base import SubprocessChannelOption
|
13
|
+
from omlish.subprocesses.wrap import subprocess_maybe_shell_wrap_exec
|
14
14
|
|
15
15
|
from .base import Command
|
16
16
|
from .base import CommandExecutor
|
@@ -10,8 +10,8 @@ import typing as ta
|
|
10
10
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
11
11
|
from omlish.lite.check import check
|
12
12
|
from omlish.shlex import shlex_maybe_quote
|
13
|
-
from omlish.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
|
14
|
-
from omlish.subprocesses import SubprocessChannelOption
|
13
|
+
from omlish.subprocesses.base import SUBPROCESS_CHANNEL_OPTION_VALUES
|
14
|
+
from omlish.subprocesses.base import SubprocessChannelOption
|
15
15
|
|
16
16
|
|
17
17
|
##
|
ominfra/scripts/journald2aws.py
CHANGED
@@ -86,9 +86,6 @@ AsyncExitStackedT = ta.TypeVar('AsyncExitStackedT', bound='AsyncExitStacked')
|
|
86
86
|
# ../../../threadworkers.py
|
87
87
|
ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
|
88
88
|
|
89
|
-
# ../../../../omlish/subprocesses.py
|
90
|
-
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
91
|
-
|
92
89
|
|
93
90
|
########################################
|
94
91
|
# ../../../../../omlish/configs/types.py
|
@@ -1945,42 +1942,107 @@ class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
|
|
1945
1942
|
|
1946
1943
|
|
1947
1944
|
########################################
|
1948
|
-
# ../../../../../omlish/os/pidfile.py
|
1945
|
+
# ../../../../../omlish/os/pidfiles/pidfile.py
|
1946
|
+
"""
|
1947
|
+
TODO:
|
1948
|
+
- reliable pid retrieval
|
1949
|
+
- contents are *ignored*, just advisory
|
1950
|
+
- check double-check:
|
1951
|
+
- 1) get pid of flock holder
|
1952
|
+
- 2) get pidfd to that
|
1953
|
+
- 3) recheck current pid of flock holder == that pid
|
1954
|
+
- racy as to if it's a different actual process as initial check, just with same pid, but due to 'identity' / semantic
|
1955
|
+
meaning of the named pidfile the processes are considered equivalent
|
1956
|
+
"""
|
1957
|
+
|
1958
|
+
|
1959
|
+
##
|
1949
1960
|
|
1950
1961
|
|
1951
1962
|
class Pidfile:
|
1952
|
-
def __init__(
|
1963
|
+
def __init__(
|
1964
|
+
self,
|
1965
|
+
path: str,
|
1966
|
+
*,
|
1967
|
+
inheritable: bool = True,
|
1968
|
+
) -> None:
|
1953
1969
|
super().__init__()
|
1954
|
-
self._path = path
|
1955
1970
|
|
1956
|
-
|
1971
|
+
self._path = path
|
1972
|
+
self._inheritable = inheritable
|
1957
1973
|
|
1958
1974
|
def __repr__(self) -> str:
|
1959
1975
|
return f'{self.__class__.__name__}({self._path!r})'
|
1960
1976
|
|
1977
|
+
#
|
1978
|
+
|
1979
|
+
_f: ta.TextIO
|
1980
|
+
|
1981
|
+
def fileno(self) -> ta.Optional[int]:
|
1982
|
+
if hasattr(self, '_f'):
|
1983
|
+
return self._f.fileno()
|
1984
|
+
else:
|
1985
|
+
return None
|
1986
|
+
|
1987
|
+
#
|
1988
|
+
|
1961
1989
|
def __enter__(self) -> 'Pidfile':
|
1962
1990
|
fd = os.open(self._path, os.O_RDWR | os.O_CREAT, 0o600)
|
1991
|
+
|
1963
1992
|
try:
|
1964
|
-
|
1993
|
+
if self._inheritable:
|
1994
|
+
os.set_inheritable(fd, True)
|
1995
|
+
|
1965
1996
|
f = os.fdopen(fd, 'r+')
|
1997
|
+
|
1966
1998
|
except Exception:
|
1967
1999
|
try:
|
1968
2000
|
os.close(fd)
|
1969
2001
|
except Exception: # noqa
|
1970
2002
|
pass
|
1971
2003
|
raise
|
2004
|
+
|
1972
2005
|
self._f = f
|
1973
2006
|
return self
|
1974
2007
|
|
1975
2008
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
2009
|
+
self.close()
|
2010
|
+
|
2011
|
+
#
|
2012
|
+
|
2013
|
+
def __getstate__(self):
|
2014
|
+
state = self.__dict__.copy()
|
2015
|
+
|
2016
|
+
if '_f' in state:
|
2017
|
+
if os.get_inheritable(fd := state.pop('_f').fileno()):
|
2018
|
+
state['__fd'] = fd
|
2019
|
+
|
2020
|
+
return state
|
2021
|
+
|
2022
|
+
def __setstate__(self, state):
|
2023
|
+
if '_f' in state:
|
2024
|
+
raise RuntimeError
|
2025
|
+
|
2026
|
+
if '__fd' in state:
|
2027
|
+
state['_f'] = os.fdopen(state.pop('__fd'), 'r+')
|
2028
|
+
|
2029
|
+
self.__dict__.update(state)
|
2030
|
+
|
2031
|
+
#
|
2032
|
+
|
2033
|
+
def close(self) -> bool:
|
2034
|
+
if not hasattr(self, '_f'):
|
2035
|
+
return False
|
2036
|
+
|
2037
|
+
self._f.close()
|
2038
|
+
del self._f
|
2039
|
+
return True
|
1979
2040
|
|
1980
2041
|
def try_lock(self) -> bool:
|
1981
2042
|
try:
|
1982
2043
|
fcntl.flock(self._f, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
1983
2044
|
return True
|
2045
|
+
|
1984
2046
|
except OSError:
|
1985
2047
|
return False
|
1986
2048
|
|
@@ -1988,27 +2050,57 @@ class Pidfile:
|
|
1988
2050
|
if not self.try_lock():
|
1989
2051
|
raise RuntimeError('Could not get lock')
|
1990
2052
|
|
2053
|
+
#
|
2054
|
+
|
1991
2055
|
def write(self, pid: ta.Optional[int] = None) -> None:
|
1992
2056
|
self.ensure_locked()
|
2057
|
+
|
1993
2058
|
if pid is None:
|
1994
2059
|
pid = os.getpid()
|
2060
|
+
|
2061
|
+
self._f.seek(0)
|
2062
|
+
self._f.truncate()
|
1995
2063
|
self._f.write(f'{pid}\n')
|
1996
2064
|
self._f.flush()
|
1997
2065
|
|
1998
2066
|
def clear(self) -> None:
|
1999
2067
|
self.ensure_locked()
|
2068
|
+
|
2000
2069
|
self._f.seek(0)
|
2001
2070
|
self._f.truncate()
|
2002
2071
|
|
2003
2072
|
def read(self) -> int:
|
2004
2073
|
if self.try_lock():
|
2005
2074
|
raise RuntimeError('Got lock')
|
2075
|
+
|
2006
2076
|
self._f.seek(0)
|
2007
|
-
return int(self._f.read())
|
2077
|
+
return int(self._f.read()) # FIXME: could be empty or hold old value, race w proc start
|
2008
2078
|
|
2009
2079
|
def kill(self, sig: int = signal.SIGTERM) -> None:
|
2010
2080
|
pid = self.read()
|
2011
|
-
os.kill(pid, sig) # FIXME: Still racy
|
2081
|
+
os.kill(pid, sig) # FIXME: Still racy - pidfd_send_signal?
|
2082
|
+
|
2083
|
+
|
2084
|
+
########################################
|
2085
|
+
# ../../../../../omlish/subprocesses/utils.py
|
2086
|
+
|
2087
|
+
|
2088
|
+
##
|
2089
|
+
|
2090
|
+
|
2091
|
+
def subprocess_close(
|
2092
|
+
proc: subprocess.Popen,
|
2093
|
+
timeout: ta.Optional[float] = None,
|
2094
|
+
) -> None:
|
2095
|
+
# TODO: terminate, sleep, kill
|
2096
|
+
if proc.stdout:
|
2097
|
+
proc.stdout.close()
|
2098
|
+
if proc.stderr:
|
2099
|
+
proc.stderr.close()
|
2100
|
+
if proc.stdin:
|
2101
|
+
proc.stdin.close()
|
2102
|
+
|
2103
|
+
proc.wait(timeout)
|
2012
2104
|
|
2013
2105
|
|
2014
2106
|
########################################
|
@@ -4245,23 +4337,7 @@ def configure_standard_logging(
|
|
4245
4337
|
|
4246
4338
|
|
4247
4339
|
########################################
|
4248
|
-
# ../../../../../omlish/subprocesses.py
|
4249
|
-
|
4250
|
-
|
4251
|
-
##
|
4252
|
-
|
4253
|
-
|
4254
|
-
# Valid channel type kwarg values:
|
4255
|
-
# - A special flag negative int
|
4256
|
-
# - A positive fd int
|
4257
|
-
# - A file-like object
|
4258
|
-
# - None
|
4259
|
-
|
4260
|
-
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
4261
|
-
'pipe': subprocess.PIPE,
|
4262
|
-
'stdout': subprocess.STDOUT,
|
4263
|
-
'devnull': subprocess.DEVNULL,
|
4264
|
-
}
|
4340
|
+
# ../../../../../omlish/subprocesses/wrap.py
|
4265
4341
|
|
4266
4342
|
|
4267
4343
|
##
|
@@ -4281,446 +4357,6 @@ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4281
4357
|
return cmd
|
4282
4358
|
|
4283
4359
|
|
4284
|
-
##
|
4285
|
-
|
4286
|
-
|
4287
|
-
def subprocess_close(
|
4288
|
-
proc: subprocess.Popen,
|
4289
|
-
timeout: ta.Optional[float] = None,
|
4290
|
-
) -> None:
|
4291
|
-
# TODO: terminate, sleep, kill
|
4292
|
-
if proc.stdout:
|
4293
|
-
proc.stdout.close()
|
4294
|
-
if proc.stderr:
|
4295
|
-
proc.stderr.close()
|
4296
|
-
if proc.stdin:
|
4297
|
-
proc.stdin.close()
|
4298
|
-
|
4299
|
-
proc.wait(timeout)
|
4300
|
-
|
4301
|
-
|
4302
|
-
##
|
4303
|
-
|
4304
|
-
|
4305
|
-
class VerboseCalledProcessError(subprocess.CalledProcessError):
|
4306
|
-
@classmethod
|
4307
|
-
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
4308
|
-
return cls(
|
4309
|
-
e.returncode,
|
4310
|
-
e.cmd,
|
4311
|
-
output=e.output,
|
4312
|
-
stderr=e.stderr,
|
4313
|
-
)
|
4314
|
-
|
4315
|
-
def __str__(self) -> str:
|
4316
|
-
msg = super().__str__()
|
4317
|
-
if self.output is not None:
|
4318
|
-
msg += f' Output: {self.output!r}'
|
4319
|
-
if self.stderr is not None:
|
4320
|
-
msg += f' Stderr: {self.stderr!r}'
|
4321
|
-
return msg
|
4322
|
-
|
4323
|
-
|
4324
|
-
class BaseSubprocesses(abc.ABC): # noqa
|
4325
|
-
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
|
4326
|
-
|
4327
|
-
def __init__(
|
4328
|
-
self,
|
4329
|
-
*,
|
4330
|
-
log: ta.Optional[logging.Logger] = None,
|
4331
|
-
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
4332
|
-
) -> None:
|
4333
|
-
super().__init__()
|
4334
|
-
|
4335
|
-
self._log = log if log is not None else self.DEFAULT_LOGGER
|
4336
|
-
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
4337
|
-
|
4338
|
-
def set_logger(self, log: ta.Optional[logging.Logger]) -> None:
|
4339
|
-
self._log = log
|
4340
|
-
|
4341
|
-
#
|
4342
|
-
|
4343
|
-
def prepare_args(
|
4344
|
-
self,
|
4345
|
-
*cmd: str,
|
4346
|
-
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
4347
|
-
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
4348
|
-
quiet: bool = False,
|
4349
|
-
shell: bool = False,
|
4350
|
-
**kwargs: ta.Any,
|
4351
|
-
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
4352
|
-
if self._log:
|
4353
|
-
self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
|
4354
|
-
if extra_env:
|
4355
|
-
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
4356
|
-
|
4357
|
-
#
|
4358
|
-
|
4359
|
-
if extra_env:
|
4360
|
-
env = {**(env if env is not None else os.environ), **extra_env}
|
4361
|
-
|
4362
|
-
#
|
4363
|
-
|
4364
|
-
if quiet and 'stderr' not in kwargs:
|
4365
|
-
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
4366
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
4367
|
-
|
4368
|
-
for chk in ('stdout', 'stderr'):
|
4369
|
-
try:
|
4370
|
-
chv = kwargs[chk]
|
4371
|
-
except KeyError:
|
4372
|
-
continue
|
4373
|
-
kwargs[chk] = SUBPROCESS_CHANNEL_OPTION_VALUES.get(chv, chv)
|
4374
|
-
|
4375
|
-
#
|
4376
|
-
|
4377
|
-
if not shell:
|
4378
|
-
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
4379
|
-
|
4380
|
-
#
|
4381
|
-
|
4382
|
-
return cmd, dict(
|
4383
|
-
env=env,
|
4384
|
-
shell=shell,
|
4385
|
-
**kwargs,
|
4386
|
-
)
|
4387
|
-
|
4388
|
-
@contextlib.contextmanager
|
4389
|
-
def wrap_call(
|
4390
|
-
self,
|
4391
|
-
*cmd: ta.Any,
|
4392
|
-
raise_verbose: bool = False,
|
4393
|
-
**kwargs: ta.Any,
|
4394
|
-
) -> ta.Iterator[None]:
|
4395
|
-
start_time = time.time()
|
4396
|
-
try:
|
4397
|
-
if self._log:
|
4398
|
-
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
4399
|
-
|
4400
|
-
yield
|
4401
|
-
|
4402
|
-
except Exception as exc: # noqa
|
4403
|
-
if self._log:
|
4404
|
-
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
4405
|
-
|
4406
|
-
if (
|
4407
|
-
raise_verbose and
|
4408
|
-
isinstance(exc, subprocess.CalledProcessError) and
|
4409
|
-
not isinstance(exc, VerboseCalledProcessError) and
|
4410
|
-
(exc.output is not None or exc.stderr is not None)
|
4411
|
-
):
|
4412
|
-
raise VerboseCalledProcessError.from_std(exc) from exc
|
4413
|
-
|
4414
|
-
raise
|
4415
|
-
|
4416
|
-
finally:
|
4417
|
-
end_time = time.time()
|
4418
|
-
elapsed_s = end_time - start_time
|
4419
|
-
|
4420
|
-
if self._log:
|
4421
|
-
self._log.debug('Subprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
4422
|
-
|
4423
|
-
@contextlib.contextmanager
|
4424
|
-
def prepare_and_wrap(
|
4425
|
-
self,
|
4426
|
-
*cmd: ta.Any,
|
4427
|
-
raise_verbose: bool = False,
|
4428
|
-
**kwargs: ta.Any,
|
4429
|
-
) -> ta.Iterator[ta.Tuple[
|
4430
|
-
ta.Tuple[ta.Any, ...],
|
4431
|
-
ta.Dict[str, ta.Any],
|
4432
|
-
]]:
|
4433
|
-
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
4434
|
-
|
4435
|
-
with self.wrap_call(
|
4436
|
-
*cmd,
|
4437
|
-
raise_verbose=raise_verbose,
|
4438
|
-
**kwargs,
|
4439
|
-
):
|
4440
|
-
yield cmd, kwargs
|
4441
|
-
|
4442
|
-
#
|
4443
|
-
|
4444
|
-
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
4445
|
-
FileNotFoundError,
|
4446
|
-
subprocess.CalledProcessError,
|
4447
|
-
)
|
4448
|
-
|
4449
|
-
def try_fn(
|
4450
|
-
self,
|
4451
|
-
fn: ta.Callable[..., T],
|
4452
|
-
*cmd: str,
|
4453
|
-
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
4454
|
-
**kwargs: ta.Any,
|
4455
|
-
) -> ta.Union[T, Exception]:
|
4456
|
-
if try_exceptions is None:
|
4457
|
-
try_exceptions = self._try_exceptions
|
4458
|
-
|
4459
|
-
try:
|
4460
|
-
return fn(*cmd, **kwargs)
|
4461
|
-
|
4462
|
-
except try_exceptions as e: # noqa
|
4463
|
-
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
4464
|
-
self._log.exception('command failed')
|
4465
|
-
return e
|
4466
|
-
|
4467
|
-
async def async_try_fn(
|
4468
|
-
self,
|
4469
|
-
fn: ta.Callable[..., ta.Awaitable[T]],
|
4470
|
-
*cmd: ta.Any,
|
4471
|
-
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
4472
|
-
**kwargs: ta.Any,
|
4473
|
-
) -> ta.Union[T, Exception]:
|
4474
|
-
if try_exceptions is None:
|
4475
|
-
try_exceptions = self._try_exceptions
|
4476
|
-
|
4477
|
-
try:
|
4478
|
-
return await fn(*cmd, **kwargs)
|
4479
|
-
|
4480
|
-
except try_exceptions as e: # noqa
|
4481
|
-
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
4482
|
-
self._log.exception('command failed')
|
4483
|
-
return e
|
4484
|
-
|
4485
|
-
|
4486
|
-
##
|
4487
|
-
|
4488
|
-
|
4489
|
-
@dc.dataclass(frozen=True)
|
4490
|
-
class SubprocessRun:
|
4491
|
-
cmd: ta.Sequence[str]
|
4492
|
-
input: ta.Any = None
|
4493
|
-
timeout: ta.Optional[float] = None
|
4494
|
-
check: bool = False
|
4495
|
-
capture_output: ta.Optional[bool] = None
|
4496
|
-
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
4497
|
-
|
4498
|
-
|
4499
|
-
@dc.dataclass(frozen=True)
|
4500
|
-
class SubprocessRunOutput(ta.Generic[T]):
|
4501
|
-
proc: T
|
4502
|
-
|
4503
|
-
returncode: int # noqa
|
4504
|
-
|
4505
|
-
stdout: ta.Optional[bytes] = None
|
4506
|
-
stderr: ta.Optional[bytes] = None
|
4507
|
-
|
4508
|
-
|
4509
|
-
class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
4510
|
-
@abc.abstractmethod
|
4511
|
-
def run_(self, run: SubprocessRun) -> SubprocessRunOutput:
|
4512
|
-
raise NotImplementedError
|
4513
|
-
|
4514
|
-
def run(
|
4515
|
-
self,
|
4516
|
-
*cmd: str,
|
4517
|
-
input: ta.Any = None, # noqa
|
4518
|
-
timeout: ta.Optional[float] = None,
|
4519
|
-
check: bool = False,
|
4520
|
-
capture_output: ta.Optional[bool] = None,
|
4521
|
-
**kwargs: ta.Any,
|
4522
|
-
) -> SubprocessRunOutput:
|
4523
|
-
return self.run_(SubprocessRun(
|
4524
|
-
cmd=cmd,
|
4525
|
-
input=input,
|
4526
|
-
timeout=timeout,
|
4527
|
-
check=check,
|
4528
|
-
capture_output=capture_output,
|
4529
|
-
kwargs=kwargs,
|
4530
|
-
))
|
4531
|
-
|
4532
|
-
#
|
4533
|
-
|
4534
|
-
@abc.abstractmethod
|
4535
|
-
def check_call(
|
4536
|
-
self,
|
4537
|
-
*cmd: str,
|
4538
|
-
stdout: ta.Any = sys.stderr,
|
4539
|
-
**kwargs: ta.Any,
|
4540
|
-
) -> None:
|
4541
|
-
raise NotImplementedError
|
4542
|
-
|
4543
|
-
@abc.abstractmethod
|
4544
|
-
def check_output(
|
4545
|
-
self,
|
4546
|
-
*cmd: str,
|
4547
|
-
**kwargs: ta.Any,
|
4548
|
-
) -> bytes:
|
4549
|
-
raise NotImplementedError
|
4550
|
-
|
4551
|
-
#
|
4552
|
-
|
4553
|
-
def check_output_str(
|
4554
|
-
self,
|
4555
|
-
*cmd: str,
|
4556
|
-
**kwargs: ta.Any,
|
4557
|
-
) -> str:
|
4558
|
-
return self.check_output(*cmd, **kwargs).decode().strip()
|
4559
|
-
|
4560
|
-
#
|
4561
|
-
|
4562
|
-
def try_call(
|
4563
|
-
self,
|
4564
|
-
*cmd: str,
|
4565
|
-
**kwargs: ta.Any,
|
4566
|
-
) -> bool:
|
4567
|
-
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
4568
|
-
return False
|
4569
|
-
else:
|
4570
|
-
return True
|
4571
|
-
|
4572
|
-
def try_output(
|
4573
|
-
self,
|
4574
|
-
*cmd: str,
|
4575
|
-
**kwargs: ta.Any,
|
4576
|
-
) -> ta.Optional[bytes]:
|
4577
|
-
if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
|
4578
|
-
return None
|
4579
|
-
else:
|
4580
|
-
return ret
|
4581
|
-
|
4582
|
-
def try_output_str(
|
4583
|
-
self,
|
4584
|
-
*cmd: str,
|
4585
|
-
**kwargs: ta.Any,
|
4586
|
-
) -> ta.Optional[str]:
|
4587
|
-
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
4588
|
-
return None
|
4589
|
-
else:
|
4590
|
-
return ret.decode().strip()
|
4591
|
-
|
4592
|
-
|
4593
|
-
##
|
4594
|
-
|
4595
|
-
|
4596
|
-
class Subprocesses(AbstractSubprocesses):
|
4597
|
-
def run_(self, run: SubprocessRun) -> SubprocessRunOutput[subprocess.CompletedProcess]:
|
4598
|
-
proc = subprocess.run(
|
4599
|
-
run.cmd,
|
4600
|
-
input=run.input,
|
4601
|
-
timeout=run.timeout,
|
4602
|
-
check=run.check,
|
4603
|
-
capture_output=run.capture_output or False,
|
4604
|
-
**(run.kwargs or {}),
|
4605
|
-
)
|
4606
|
-
|
4607
|
-
return SubprocessRunOutput(
|
4608
|
-
proc=proc,
|
4609
|
-
|
4610
|
-
returncode=proc.returncode,
|
4611
|
-
|
4612
|
-
stdout=proc.stdout, # noqa
|
4613
|
-
stderr=proc.stderr, # noqa
|
4614
|
-
)
|
4615
|
-
|
4616
|
-
def check_call(
|
4617
|
-
self,
|
4618
|
-
*cmd: str,
|
4619
|
-
stdout: ta.Any = sys.stderr,
|
4620
|
-
**kwargs: ta.Any,
|
4621
|
-
) -> None:
|
4622
|
-
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
4623
|
-
subprocess.check_call(cmd, **kwargs)
|
4624
|
-
|
4625
|
-
def check_output(
|
4626
|
-
self,
|
4627
|
-
*cmd: str,
|
4628
|
-
**kwargs: ta.Any,
|
4629
|
-
) -> bytes:
|
4630
|
-
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
4631
|
-
return subprocess.check_output(cmd, **kwargs)
|
4632
|
-
|
4633
|
-
|
4634
|
-
subprocesses = Subprocesses()
|
4635
|
-
|
4636
|
-
|
4637
|
-
##
|
4638
|
-
|
4639
|
-
|
4640
|
-
class AbstractAsyncSubprocesses(BaseSubprocesses):
|
4641
|
-
@abc.abstractmethod
|
4642
|
-
async def run_(self, run: SubprocessRun) -> SubprocessRunOutput:
|
4643
|
-
raise NotImplementedError
|
4644
|
-
|
4645
|
-
def run(
|
4646
|
-
self,
|
4647
|
-
*cmd: str,
|
4648
|
-
input: ta.Any = None, # noqa
|
4649
|
-
timeout: ta.Optional[float] = None,
|
4650
|
-
check: bool = False,
|
4651
|
-
capture_output: ta.Optional[bool] = None,
|
4652
|
-
**kwargs: ta.Any,
|
4653
|
-
) -> ta.Awaitable[SubprocessRunOutput]:
|
4654
|
-
return self.run_(SubprocessRun(
|
4655
|
-
cmd=cmd,
|
4656
|
-
input=input,
|
4657
|
-
timeout=timeout,
|
4658
|
-
check=check,
|
4659
|
-
capture_output=capture_output,
|
4660
|
-
kwargs=kwargs,
|
4661
|
-
))
|
4662
|
-
|
4663
|
-
#
|
4664
|
-
|
4665
|
-
@abc.abstractmethod
|
4666
|
-
async def check_call(
|
4667
|
-
self,
|
4668
|
-
*cmd: str,
|
4669
|
-
stdout: ta.Any = sys.stderr,
|
4670
|
-
**kwargs: ta.Any,
|
4671
|
-
) -> None:
|
4672
|
-
raise NotImplementedError
|
4673
|
-
|
4674
|
-
@abc.abstractmethod
|
4675
|
-
async def check_output(
|
4676
|
-
self,
|
4677
|
-
*cmd: str,
|
4678
|
-
**kwargs: ta.Any,
|
4679
|
-
) -> bytes:
|
4680
|
-
raise NotImplementedError
|
4681
|
-
|
4682
|
-
#
|
4683
|
-
|
4684
|
-
async def check_output_str(
|
4685
|
-
self,
|
4686
|
-
*cmd: str,
|
4687
|
-
**kwargs: ta.Any,
|
4688
|
-
) -> str:
|
4689
|
-
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
4690
|
-
|
4691
|
-
#
|
4692
|
-
|
4693
|
-
async def try_call(
|
4694
|
-
self,
|
4695
|
-
*cmd: str,
|
4696
|
-
**kwargs: ta.Any,
|
4697
|
-
) -> bool:
|
4698
|
-
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
4699
|
-
return False
|
4700
|
-
else:
|
4701
|
-
return True
|
4702
|
-
|
4703
|
-
async def try_output(
|
4704
|
-
self,
|
4705
|
-
*cmd: str,
|
4706
|
-
**kwargs: ta.Any,
|
4707
|
-
) -> ta.Optional[bytes]:
|
4708
|
-
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
4709
|
-
return None
|
4710
|
-
else:
|
4711
|
-
return ret
|
4712
|
-
|
4713
|
-
async def try_output_str(
|
4714
|
-
self,
|
4715
|
-
*cmd: str,
|
4716
|
-
**kwargs: ta.Any,
|
4717
|
-
) -> ta.Optional[str]:
|
4718
|
-
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
4719
|
-
return None
|
4720
|
-
else:
|
4721
|
-
return ret.decode().strip()
|
4722
|
-
|
4723
|
-
|
4724
4360
|
########################################
|
4725
4361
|
# ../poster.py
|
4726
4362
|
"""
|