ominfra 0.0.0.dev151__py3-none-any.whl → 0.0.0.dev153__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/manage/bootstrap.py +3 -0
- ominfra/manage/bootstrap_.py +1 -0
- ominfra/manage/commands/interp.py +0 -3
- ominfra/manage/commands/subprocess.py +0 -3
- ominfra/manage/deploy/{command.py → commands.py} +0 -3
- ominfra/manage/deploy/inject.py +2 -2
- ominfra/manage/inject.py +8 -1
- ominfra/manage/main.py +7 -7
- ominfra/manage/remote/_main.py +3 -3
- ominfra/manage/remote/config.py +2 -0
- ominfra/manage/remote/connection.py +48 -0
- ominfra/manage/remote/execution.py +90 -12
- ominfra/manage/remote/inject.py +19 -4
- ominfra/manage/system/__init__.py +0 -0
- ominfra/manage/system/commands.py +24 -0
- ominfra/manage/system/config.py +8 -0
- ominfra/manage/system/inject.py +54 -0
- ominfra/manage/system/packages.py +106 -0
- ominfra/manage/system/types.py +5 -0
- ominfra/scripts/journald2aws.py +68 -68
- ominfra/scripts/manage.py +483 -83
- ominfra/scripts/supervisor.py +157 -157
- ominfra/supervisor/main.py +1 -1
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/RECORD +30 -24
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev151.dist-info → ominfra-0.0.0.dev153.dist-info}/top_level.txt +0 -0
ominfra/scripts/manage.py
CHANGED
@@ -68,7 +68,7 @@ VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalTy
|
|
68
68
|
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
|
69
69
|
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
|
70
70
|
|
71
|
-
# ../../omlish/
|
71
|
+
# ../../omlish/asyncs/asyncio/timeouts.py
|
72
72
|
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
73
73
|
|
74
74
|
# ../../omlish/lite/cached.py
|
@@ -103,7 +103,10 @@ InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
|
103
103
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
104
104
|
|
105
105
|
# ../../omlish/lite/subprocesses.py
|
106
|
-
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull']
|
106
|
+
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
107
|
+
|
108
|
+
# system/packages.py
|
109
|
+
SystemPackageOrStr = ta.Union['SystemPackage', str]
|
107
110
|
|
108
111
|
|
109
112
|
########################################
|
@@ -524,6 +527,22 @@ class MainConfig:
|
|
524
527
|
debug: bool = False
|
525
528
|
|
526
529
|
|
530
|
+
########################################
|
531
|
+
# ../system/config.py
|
532
|
+
|
533
|
+
|
534
|
+
@dc.dataclass(frozen=True)
|
535
|
+
class SystemConfig:
|
536
|
+
platform: ta.Optional[str] = None
|
537
|
+
|
538
|
+
|
539
|
+
########################################
|
540
|
+
# ../system/types.py
|
541
|
+
|
542
|
+
|
543
|
+
SystemPlatform = ta.NewType('SystemPlatform', str)
|
544
|
+
|
545
|
+
|
527
546
|
########################################
|
528
547
|
# ../../pyremote.py
|
529
548
|
"""
|
@@ -1044,10 +1063,47 @@ class PyremoteBootstrapDriver:
|
|
1044
1063
|
|
1045
1064
|
|
1046
1065
|
########################################
|
1047
|
-
# ../../../omlish/
|
1066
|
+
# ../../../omlish/asyncs/asyncio/channels.py
|
1048
1067
|
|
1049
1068
|
|
1050
|
-
|
1069
|
+
class AsyncioBytesChannelTransport(asyncio.Transport):
|
1070
|
+
def __init__(self, reader: asyncio.StreamReader) -> None:
|
1071
|
+
super().__init__()
|
1072
|
+
|
1073
|
+
self.reader = reader
|
1074
|
+
self.closed: asyncio.Future = asyncio.Future()
|
1075
|
+
|
1076
|
+
# @ta.override
|
1077
|
+
def write(self, data: bytes) -> None:
|
1078
|
+
self.reader.feed_data(data)
|
1079
|
+
|
1080
|
+
# @ta.override
|
1081
|
+
def close(self) -> None:
|
1082
|
+
self.reader.feed_eof()
|
1083
|
+
if not self.closed.done():
|
1084
|
+
self.closed.set_result(True)
|
1085
|
+
|
1086
|
+
# @ta.override
|
1087
|
+
def is_closing(self) -> bool:
|
1088
|
+
return self.closed.done()
|
1089
|
+
|
1090
|
+
|
1091
|
+
def asyncio_create_bytes_channel(
|
1092
|
+
loop: ta.Any = None,
|
1093
|
+
) -> ta.Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
|
1094
|
+
if loop is None:
|
1095
|
+
loop = asyncio.get_running_loop()
|
1096
|
+
|
1097
|
+
reader = asyncio.StreamReader()
|
1098
|
+
protocol = asyncio.StreamReaderProtocol(reader)
|
1099
|
+
transport = AsyncioBytesChannelTransport(reader)
|
1100
|
+
writer = asyncio.StreamWriter(transport, protocol, reader, loop)
|
1101
|
+
|
1102
|
+
return reader, writer
|
1103
|
+
|
1104
|
+
|
1105
|
+
########################################
|
1106
|
+
# ../../../omlish/asyncs/asyncio/streams.py
|
1051
1107
|
|
1052
1108
|
|
1053
1109
|
ASYNCIO_DEFAULT_BUFFER_LIMIT = 2 ** 16
|
@@ -1091,7 +1147,8 @@ async def asyncio_open_stream_writer(
|
|
1091
1147
|
)
|
1092
1148
|
|
1093
1149
|
|
1094
|
-
|
1150
|
+
########################################
|
1151
|
+
# ../../../omlish/asyncs/asyncio/timeouts.py
|
1095
1152
|
|
1096
1153
|
|
1097
1154
|
def asyncio_maybe_timeout(
|
@@ -1611,30 +1668,6 @@ class Checks:
|
|
1611
1668
|
check = Checks()
|
1612
1669
|
|
1613
1670
|
|
1614
|
-
########################################
|
1615
|
-
# ../../../omlish/lite/deathsig.py
|
1616
|
-
|
1617
|
-
|
1618
|
-
LINUX_PR_SET_PDEATHSIG = 1 # Second arg is a signal
|
1619
|
-
LINUX_PR_GET_PDEATHSIG = 2 # Second arg is a ptr to return the signal
|
1620
|
-
|
1621
|
-
|
1622
|
-
def set_process_deathsig(sig: int) -> bool:
|
1623
|
-
if sys.platform == 'linux':
|
1624
|
-
libc = ct.CDLL('libc.so.6')
|
1625
|
-
|
1626
|
-
# int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
1627
|
-
libc.prctl.restype = ct.c_int
|
1628
|
-
libc.prctl.argtypes = [ct.c_int, ct.c_ulong, ct.c_ulong, ct.c_ulong, ct.c_ulong]
|
1629
|
-
|
1630
|
-
libc.prctl(LINUX_PR_SET_PDEATHSIG, sig, 0, 0, 0, 0)
|
1631
|
-
|
1632
|
-
return True
|
1633
|
-
|
1634
|
-
else:
|
1635
|
-
return False
|
1636
|
-
|
1637
|
-
|
1638
1671
|
########################################
|
1639
1672
|
# ../../../omlish/lite/json.py
|
1640
1673
|
|
@@ -1880,6 +1913,30 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
1880
1913
|
return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
|
1881
1914
|
|
1882
1915
|
|
1916
|
+
########################################
|
1917
|
+
# ../../../omlish/os/deathsig.py
|
1918
|
+
|
1919
|
+
|
1920
|
+
LINUX_PR_SET_PDEATHSIG = 1 # Second arg is a signal
|
1921
|
+
LINUX_PR_GET_PDEATHSIG = 2 # Second arg is a ptr to return the signal
|
1922
|
+
|
1923
|
+
|
1924
|
+
def set_process_deathsig(sig: int) -> bool:
|
1925
|
+
if sys.platform == 'linux':
|
1926
|
+
libc = ct.CDLL('libc.so.6')
|
1927
|
+
|
1928
|
+
# int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
1929
|
+
libc.prctl.restype = ct.c_int
|
1930
|
+
libc.prctl.argtypes = [ct.c_int, ct.c_ulong, ct.c_ulong, ct.c_ulong, ct.c_ulong]
|
1931
|
+
|
1932
|
+
libc.prctl(LINUX_PR_SET_PDEATHSIG, sig, 0, 0, 0, 0)
|
1933
|
+
|
1934
|
+
return True
|
1935
|
+
|
1936
|
+
else:
|
1937
|
+
return False
|
1938
|
+
|
1939
|
+
|
1883
1940
|
########################################
|
1884
1941
|
# ../../../omdev/packaging/specifiers.py
|
1885
1942
|
# Copyright (c) Donald Stufft and individual contributors.
|
@@ -2572,6 +2629,8 @@ class RemoteConfig:
|
|
2572
2629
|
|
2573
2630
|
heartbeat_interval_s: float = 3.
|
2574
2631
|
|
2632
|
+
use_in_process_remote_executor: bool = False
|
2633
|
+
|
2575
2634
|
|
2576
2635
|
########################################
|
2577
2636
|
# ../remote/payload.py
|
@@ -2618,6 +2677,8 @@ def get_remote_payload_src(
|
|
2618
2677
|
TODO:
|
2619
2678
|
- default command
|
2620
2679
|
- auto match all underscores to hyphens
|
2680
|
+
- pre-run, post-run hooks
|
2681
|
+
- exitstack?
|
2621
2682
|
"""
|
2622
2683
|
|
2623
2684
|
|
@@ -2737,11 +2798,12 @@ class ArgparseCli:
|
|
2737
2798
|
|
2738
2799
|
self._args, self._unknown_args = self.get_parser().parse_known_args(self._argv)
|
2739
2800
|
|
2801
|
+
#
|
2802
|
+
|
2740
2803
|
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
2741
2804
|
super().__init_subclass__(**kwargs)
|
2742
2805
|
|
2743
2806
|
ns = cls.__dict__
|
2744
|
-
|
2745
2807
|
objs = {}
|
2746
2808
|
mro = cls.__mro__[::-1]
|
2747
2809
|
for bns in [bcls.__dict__ for bcls in reversed(mro)] + [ns]:
|
@@ -2754,24 +2816,33 @@ class ArgparseCli:
|
|
2754
2816
|
elif k in objs:
|
2755
2817
|
del [k]
|
2756
2818
|
|
2819
|
+
#
|
2820
|
+
|
2757
2821
|
anns = ta.get_type_hints(_ArgparseCliAnnotationBox({
|
2758
2822
|
**{k: v for bcls in reversed(mro) for k, v in getattr(bcls, '__annotations__', {}).items()},
|
2759
2823
|
**ns.get('__annotations__', {}),
|
2760
2824
|
}), globalns=ns.get('__globals__', {}))
|
2761
2825
|
|
2826
|
+
#
|
2827
|
+
|
2762
2828
|
if '_parser' in ns:
|
2763
2829
|
parser = check.isinstance(ns['_parser'], argparse.ArgumentParser)
|
2764
2830
|
else:
|
2765
2831
|
parser = argparse.ArgumentParser()
|
2766
2832
|
setattr(cls, '_parser', parser)
|
2767
2833
|
|
2834
|
+
#
|
2835
|
+
|
2768
2836
|
subparsers = parser.add_subparsers()
|
2837
|
+
|
2769
2838
|
for att, obj in objs.items():
|
2770
2839
|
if isinstance(obj, ArgparseCommand):
|
2771
2840
|
if obj.parent is not None:
|
2772
2841
|
raise NotImplementedError
|
2842
|
+
|
2773
2843
|
for cn in [obj.name, *(obj.aliases or [])]:
|
2774
|
-
|
2844
|
+
subparser = subparsers.add_parser(cn)
|
2845
|
+
|
2775
2846
|
for arg in (obj.args or []):
|
2776
2847
|
if (
|
2777
2848
|
len(arg.args) == 1 and
|
@@ -2779,29 +2850,34 @@ class ArgparseCli:
|
|
2779
2850
|
not (n := check.isinstance(arg.args[0], str)).startswith('-') and
|
2780
2851
|
'metavar' not in arg.kwargs
|
2781
2852
|
):
|
2782
|
-
|
2853
|
+
subparser.add_argument(
|
2783
2854
|
n.replace('-', '_'),
|
2784
2855
|
**arg.kwargs,
|
2785
2856
|
metavar=n,
|
2786
2857
|
)
|
2787
2858
|
else:
|
2788
|
-
|
2789
|
-
|
2859
|
+
subparser.add_argument(*arg.args, **arg.kwargs)
|
2860
|
+
|
2861
|
+
subparser.set_defaults(_cmd=obj)
|
2790
2862
|
|
2791
2863
|
elif isinstance(obj, ArgparseArg):
|
2792
2864
|
if att in anns:
|
2793
|
-
|
2794
|
-
obj.kwargs = {**
|
2865
|
+
ann_kwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
2866
|
+
obj.kwargs = {**ann_kwargs, **obj.kwargs}
|
2867
|
+
|
2795
2868
|
if not obj.dest:
|
2796
2869
|
if 'dest' in obj.kwargs:
|
2797
2870
|
obj.dest = obj.kwargs['dest']
|
2798
2871
|
else:
|
2799
2872
|
obj.dest = obj.kwargs['dest'] = att # type: ignore
|
2873
|
+
|
2800
2874
|
parser.add_argument(*obj.args, **obj.kwargs)
|
2801
2875
|
|
2802
2876
|
else:
|
2803
2877
|
raise TypeError(obj)
|
2804
2878
|
|
2879
|
+
#
|
2880
|
+
|
2805
2881
|
_parser: ta.ClassVar[argparse.ArgumentParser]
|
2806
2882
|
|
2807
2883
|
@classmethod
|
@@ -2820,10 +2896,12 @@ class ArgparseCli:
|
|
2820
2896
|
def unknown_args(self) -> ta.Sequence[str]:
|
2821
2897
|
return self._unknown_args
|
2822
2898
|
|
2823
|
-
|
2824
|
-
return cmd.__get__(self, type(self))()
|
2899
|
+
#
|
2825
2900
|
|
2826
|
-
def
|
2901
|
+
def _bind_cli_cmd(self, cmd: ArgparseCommand) -> ta.Callable:
|
2902
|
+
return cmd.__get__(self, type(self))
|
2903
|
+
|
2904
|
+
def prepare_cli_run(self) -> ta.Optional[ta.Callable]:
|
2827
2905
|
cmd = getattr(self.args, '_cmd', None)
|
2828
2906
|
|
2829
2907
|
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
@@ -2835,12 +2913,34 @@ class ArgparseCli:
|
|
2835
2913
|
|
2836
2914
|
if cmd is None:
|
2837
2915
|
self.get_parser().print_help()
|
2916
|
+
return None
|
2917
|
+
|
2918
|
+
return self._bind_cli_cmd(cmd)
|
2919
|
+
|
2920
|
+
#
|
2921
|
+
|
2922
|
+
def cli_run(self) -> ta.Optional[int]:
|
2923
|
+
if (fn := self.prepare_cli_run()) is None:
|
2838
2924
|
return 0
|
2839
2925
|
|
2840
|
-
return
|
2926
|
+
return fn()
|
2927
|
+
|
2928
|
+
def cli_run_and_exit(self) -> ta.NoReturn:
|
2929
|
+
sys.exit(rc if isinstance(rc := self.cli_run(), int) else 0)
|
2930
|
+
|
2931
|
+
def __call__(self, *, exit: bool = False) -> ta.Optional[int]: # noqa
|
2932
|
+
if exit:
|
2933
|
+
return self.cli_run_and_exit()
|
2934
|
+
else:
|
2935
|
+
return self.cli_run()
|
2936
|
+
|
2937
|
+
#
|
2938
|
+
|
2939
|
+
async def async_cli_run(self) -> ta.Optional[int]:
|
2940
|
+
if (fn := self.prepare_cli_run()) is None:
|
2941
|
+
return 0
|
2841
2942
|
|
2842
|
-
|
2843
|
-
sys.exit(rc if isinstance(rc := self(), int) else 0)
|
2943
|
+
return await fn()
|
2844
2944
|
|
2845
2945
|
|
2846
2946
|
########################################
|
@@ -4565,6 +4665,8 @@ class MainBootstrap:
|
|
4565
4665
|
|
4566
4666
|
remote_config: RemoteConfig = RemoteConfig()
|
4567
4667
|
|
4668
|
+
system_config: SystemConfig = SystemConfig()
|
4669
|
+
|
4568
4670
|
|
4569
4671
|
########################################
|
4570
4672
|
# ../commands/execution.py
|
@@ -4614,7 +4716,7 @@ def install_command_marshaling(
|
|
4614
4716
|
|
4615
4717
|
|
4616
4718
|
########################################
|
4617
|
-
# ../deploy/
|
4719
|
+
# ../deploy/commands.py
|
4618
4720
|
|
4619
4721
|
|
4620
4722
|
##
|
@@ -4627,9 +4729,6 @@ class DeployCommand(Command['DeployCommand.Output']):
|
|
4627
4729
|
pass
|
4628
4730
|
|
4629
4731
|
|
4630
|
-
##
|
4631
|
-
|
4632
|
-
|
4633
4732
|
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
4634
4733
|
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
4635
4734
|
log.info('Deploying!')
|
@@ -4728,6 +4827,27 @@ class RemoteChannelImpl(RemoteChannel):
|
|
4728
4827
|
return await self._recv_obj(ty)
|
4729
4828
|
|
4730
4829
|
|
4830
|
+
########################################
|
4831
|
+
# ../system/commands.py
|
4832
|
+
|
4833
|
+
|
4834
|
+
##
|
4835
|
+
|
4836
|
+
|
4837
|
+
@dc.dataclass(frozen=True)
|
4838
|
+
class CheckSystemPackageCommand(Command['CheckSystemPackageCommand.Output']):
|
4839
|
+
@dc.dataclass(frozen=True)
|
4840
|
+
class Output(Command.Output):
|
4841
|
+
pass
|
4842
|
+
|
4843
|
+
|
4844
|
+
class CheckSystemPackageCommandExecutor(CommandExecutor[CheckSystemPackageCommand, CheckSystemPackageCommand.Output]):
|
4845
|
+
async def execute(self, cmd: CheckSystemPackageCommand) -> CheckSystemPackageCommand.Output:
|
4846
|
+
log.info('Checking system package!')
|
4847
|
+
|
4848
|
+
return CheckSystemPackageCommand.Output()
|
4849
|
+
|
4850
|
+
|
4731
4851
|
########################################
|
4732
4852
|
# ../../../omlish/lite/subprocesses.py
|
4733
4853
|
|
@@ -4914,6 +5034,10 @@ def subprocess_close(
|
|
4914
5034
|
|
4915
5035
|
########################################
|
4916
5036
|
# ../remote/execution.py
|
5037
|
+
"""
|
5038
|
+
TODO:
|
5039
|
+
- sequence all messages
|
5040
|
+
"""
|
4917
5041
|
|
4918
5042
|
|
4919
5043
|
##
|
@@ -4992,38 +5116,80 @@ class _RemoteLogHandler(logging.Handler):
|
|
4992
5116
|
|
4993
5117
|
|
4994
5118
|
class _RemoteCommandHandler:
|
5119
|
+
DEFAULT_PING_INTERVAL_S: float = 3.
|
5120
|
+
|
4995
5121
|
def __init__(
|
4996
5122
|
self,
|
4997
5123
|
chan: RemoteChannel,
|
4998
5124
|
executor: CommandExecutor,
|
4999
5125
|
*,
|
5000
5126
|
stop: ta.Optional[asyncio.Event] = None,
|
5127
|
+
ping_interval_s: float = DEFAULT_PING_INTERVAL_S,
|
5001
5128
|
) -> None:
|
5002
5129
|
super().__init__()
|
5003
5130
|
|
5004
5131
|
self._chan = chan
|
5005
5132
|
self._executor = executor
|
5006
5133
|
self._stop = stop if stop is not None else asyncio.Event()
|
5134
|
+
self._ping_interval_s = ping_interval_s
|
5007
5135
|
|
5008
5136
|
self._cmds_by_seq: ta.Dict[int, _RemoteCommandHandler._Command] = {}
|
5009
5137
|
|
5138
|
+
self._last_ping_send: float = 0.
|
5139
|
+
self._ping_in_flight: bool = False
|
5140
|
+
self._last_ping_recv: ta.Optional[float] = None
|
5141
|
+
|
5142
|
+
def stop(self) -> None:
|
5143
|
+
self._stop.set()
|
5144
|
+
|
5010
5145
|
@dc.dataclass(frozen=True)
|
5011
5146
|
class _Command:
|
5012
5147
|
req: _RemoteProtocol.CommandRequest
|
5013
5148
|
fut: asyncio.Future
|
5014
5149
|
|
5015
5150
|
async def run(self) -> None:
|
5151
|
+
log.debug('_RemoteCommandHandler loop start: %r', self)
|
5152
|
+
|
5016
5153
|
stop_task = asyncio.create_task(self._stop.wait())
|
5017
5154
|
recv_task: ta.Optional[asyncio.Task] = None
|
5018
5155
|
|
5019
5156
|
while not self._stop.is_set():
|
5020
5157
|
if recv_task is None:
|
5021
|
-
recv_task = asyncio.create_task(_RemoteProtocol.
|
5158
|
+
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
5159
|
+
|
5160
|
+
if not self._ping_in_flight:
|
5161
|
+
if not self._last_ping_recv:
|
5162
|
+
ping_wait_time = 0.
|
5163
|
+
else:
|
5164
|
+
ping_wait_time = self._ping_interval_s - (time.time() - self._last_ping_recv)
|
5165
|
+
else:
|
5166
|
+
ping_wait_time = float('inf')
|
5167
|
+
wait_time = min(self._ping_interval_s, ping_wait_time)
|
5168
|
+
log.debug('_RemoteCommandHandler loop wait: %f', wait_time)
|
5169
|
+
|
5170
|
+
done, pending = await asyncio.wait(
|
5171
|
+
[
|
5172
|
+
stop_task,
|
5173
|
+
recv_task,
|
5174
|
+
],
|
5175
|
+
return_when=asyncio.FIRST_COMPLETED,
|
5176
|
+
timeout=wait_time,
|
5177
|
+
)
|
5022
5178
|
|
5023
|
-
|
5024
|
-
|
5025
|
-
|
5026
|
-
|
5179
|
+
#
|
5180
|
+
|
5181
|
+
if (
|
5182
|
+
(time.time() - self._last_ping_send >= self._ping_interval_s) and
|
5183
|
+
not self._ping_in_flight
|
5184
|
+
):
|
5185
|
+
now = time.time()
|
5186
|
+
self._last_ping_send = now
|
5187
|
+
self._ping_in_flight = True
|
5188
|
+
await _RemoteProtocol.PingRequest(
|
5189
|
+
time=now,
|
5190
|
+
).send(self._chan)
|
5191
|
+
|
5192
|
+
#
|
5027
5193
|
|
5028
5194
|
if recv_task in done:
|
5029
5195
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -5037,6 +5203,20 @@ class _RemoteCommandHandler:
|
|
5037
5203
|
|
5038
5204
|
await self._handle_message(msg)
|
5039
5205
|
|
5206
|
+
log.debug('_RemoteCommandHandler loop stopping: %r', self)
|
5207
|
+
|
5208
|
+
for task in [
|
5209
|
+
stop_task,
|
5210
|
+
recv_task,
|
5211
|
+
]:
|
5212
|
+
if task is not None and not task.done():
|
5213
|
+
task.cancel()
|
5214
|
+
|
5215
|
+
for cmd in self._cmds_by_seq.values():
|
5216
|
+
cmd.fut.cancel()
|
5217
|
+
|
5218
|
+
log.debug('_RemoteCommandHandler loop exited: %r', self)
|
5219
|
+
|
5040
5220
|
async def _handle_message(self, msg: _RemoteProtocol.Message) -> None:
|
5041
5221
|
if isinstance(msg, _RemoteProtocol.PingRequest):
|
5042
5222
|
log.debug('Ping: %r', msg)
|
@@ -5044,6 +5224,12 @@ class _RemoteCommandHandler:
|
|
5044
5224
|
time=msg.time,
|
5045
5225
|
).send(self._chan)
|
5046
5226
|
|
5227
|
+
elif isinstance(msg, _RemoteProtocol.PingResponse):
|
5228
|
+
latency_s = time.time() - msg.time
|
5229
|
+
log.debug('Pong: %0.2f ms %r', latency_s * 1000., msg)
|
5230
|
+
self._last_ping_recv = time.time()
|
5231
|
+
self._ping_in_flight = False
|
5232
|
+
|
5047
5233
|
elif isinstance(msg, _RemoteProtocol.CommandRequest):
|
5048
5234
|
fut = asyncio.create_task(self._handle_command_request(msg))
|
5049
5235
|
self._cmds_by_seq[msg.seq] = _RemoteCommandHandler._Command(
|
@@ -5125,16 +5311,23 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5125
5311
|
if recv_task is None:
|
5126
5312
|
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
5127
5313
|
|
5128
|
-
done, pending = await asyncio.wait(
|
5129
|
-
|
5130
|
-
|
5131
|
-
|
5132
|
-
|
5314
|
+
done, pending = await asyncio.wait(
|
5315
|
+
[
|
5316
|
+
stop_task,
|
5317
|
+
queue_task,
|
5318
|
+
recv_task,
|
5319
|
+
],
|
5320
|
+
return_when=asyncio.FIRST_COMPLETED,
|
5321
|
+
)
|
5322
|
+
|
5323
|
+
#
|
5133
5324
|
|
5134
5325
|
if queue_task in done:
|
5135
5326
|
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
5136
5327
|
queue_task = None
|
5137
|
-
await self.
|
5328
|
+
await self._handle_queued_request(req)
|
5329
|
+
|
5330
|
+
#
|
5138
5331
|
|
5139
5332
|
if recv_task in done:
|
5140
5333
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -5164,7 +5357,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5164
5357
|
|
5165
5358
|
log.debug('RemoteCommandExecutor loop exited: %r', self)
|
5166
5359
|
|
5167
|
-
async def
|
5360
|
+
async def _handle_queued_request(self, req: _Request) -> None:
|
5168
5361
|
self._reqs_by_seq[req.seq] = req
|
5169
5362
|
await _RemoteProtocol.CommandRequest(
|
5170
5363
|
seq=req.seq,
|
@@ -5178,6 +5371,10 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5178
5371
|
time=msg.time,
|
5179
5372
|
).send(self._chan)
|
5180
5373
|
|
5374
|
+
elif isinstance(msg, _RemoteProtocol.PingResponse):
|
5375
|
+
latency_s = time.time() - msg.time
|
5376
|
+
log.debug('Pong: %0.2f ms %r', latency_s * 1000., msg)
|
5377
|
+
|
5181
5378
|
elif isinstance(msg, _RemoteProtocol.LogResponse):
|
5182
5379
|
log.info(msg.s)
|
5183
5380
|
|
@@ -5394,22 +5591,25 @@ async def asyncio_subprocess_communicate(
|
|
5394
5591
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
5395
5592
|
|
5396
5593
|
|
5397
|
-
|
5398
|
-
|
5399
|
-
|
5400
|
-
async def _asyncio_subprocess_check_run(
|
5594
|
+
async def asyncio_subprocess_run(
|
5401
5595
|
*args: str,
|
5402
5596
|
input: ta.Any = None, # noqa
|
5403
5597
|
timeout: ta.Optional[float] = None,
|
5598
|
+
check: bool = False, # noqa
|
5599
|
+
capture_output: ta.Optional[bool] = None,
|
5404
5600
|
**kwargs: ta.Any,
|
5405
5601
|
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
5602
|
+
if capture_output:
|
5603
|
+
kwargs.setdefault('stdout', subprocess.PIPE)
|
5604
|
+
kwargs.setdefault('stderr', subprocess.PIPE)
|
5605
|
+
|
5406
5606
|
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
5407
5607
|
|
5408
5608
|
proc: asyncio.subprocess.Process
|
5409
5609
|
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
5410
5610
|
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
5411
5611
|
|
5412
|
-
if proc.returncode:
|
5612
|
+
if check and proc.returncode:
|
5413
5613
|
raise subprocess.CalledProcessError(
|
5414
5614
|
proc.returncode,
|
5415
5615
|
args,
|
@@ -5420,6 +5620,9 @@ async def _asyncio_subprocess_check_run(
|
|
5420
5620
|
return stdout, stderr
|
5421
5621
|
|
5422
5622
|
|
5623
|
+
##
|
5624
|
+
|
5625
|
+
|
5423
5626
|
async def asyncio_subprocess_check_call(
|
5424
5627
|
*args: str,
|
5425
5628
|
stdout: ta.Any = sys.stderr,
|
@@ -5427,11 +5630,12 @@ async def asyncio_subprocess_check_call(
|
|
5427
5630
|
timeout: ta.Optional[float] = None,
|
5428
5631
|
**kwargs: ta.Any,
|
5429
5632
|
) -> None:
|
5430
|
-
_, _ = await
|
5633
|
+
_, _ = await asyncio_subprocess_run(
|
5431
5634
|
*args,
|
5432
5635
|
stdout=stdout,
|
5433
5636
|
input=input,
|
5434
5637
|
timeout=timeout,
|
5638
|
+
check=True,
|
5435
5639
|
**kwargs,
|
5436
5640
|
)
|
5437
5641
|
|
@@ -5442,11 +5646,12 @@ async def asyncio_subprocess_check_output(
|
|
5442
5646
|
timeout: ta.Optional[float] = None,
|
5443
5647
|
**kwargs: ta.Any,
|
5444
5648
|
) -> bytes:
|
5445
|
-
stdout, stderr = await
|
5649
|
+
stdout, stderr = await asyncio_subprocess_run(
|
5446
5650
|
*args,
|
5447
5651
|
stdout=asyncio.subprocess.PIPE,
|
5448
5652
|
input=input,
|
5449
5653
|
timeout=timeout,
|
5654
|
+
check=True,
|
5450
5655
|
**kwargs,
|
5451
5656
|
)
|
5452
5657
|
|
@@ -5641,9 +5846,6 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
5641
5846
|
stderr: ta.Optional[bytes] = None
|
5642
5847
|
|
5643
5848
|
|
5644
|
-
##
|
5645
|
-
|
5646
|
-
|
5647
5849
|
class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
|
5648
5850
|
async def execute(self, cmd: SubprocessCommand) -> SubprocessCommand.Output:
|
5649
5851
|
proc: asyncio.subprocess.Process
|
@@ -5925,6 +6127,102 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
5925
6127
|
pass
|
5926
6128
|
|
5927
6129
|
|
6130
|
+
########################################
|
6131
|
+
# ../system/packages.py
|
6132
|
+
"""
|
6133
|
+
TODO:
|
6134
|
+
- yum/rpm
|
6135
|
+
"""
|
6136
|
+
|
6137
|
+
|
6138
|
+
@dc.dataclass(frozen=True)
|
6139
|
+
class SystemPackage:
|
6140
|
+
name: str
|
6141
|
+
version: ta.Optional[str] = None
|
6142
|
+
|
6143
|
+
|
6144
|
+
class SystemPackageManager(abc.ABC):
|
6145
|
+
@abc.abstractmethod
|
6146
|
+
def update(self) -> ta.Awaitable[None]:
|
6147
|
+
raise NotImplementedError
|
6148
|
+
|
6149
|
+
@abc.abstractmethod
|
6150
|
+
def upgrade(self) -> ta.Awaitable[None]:
|
6151
|
+
raise NotImplementedError
|
6152
|
+
|
6153
|
+
@abc.abstractmethod
|
6154
|
+
def install(self, *packages: SystemPackageOrStr) -> ta.Awaitable[None]:
|
6155
|
+
raise NotImplementedError
|
6156
|
+
|
6157
|
+
@abc.abstractmethod
|
6158
|
+
def query(self, *packages: SystemPackageOrStr) -> ta.Awaitable[ta.Mapping[str, SystemPackage]]:
|
6159
|
+
raise NotImplementedError
|
6160
|
+
|
6161
|
+
|
6162
|
+
class BrewSystemPackageManager(SystemPackageManager):
|
6163
|
+
async def update(self) -> None:
|
6164
|
+
await asyncio_subprocess_check_call('brew', 'update')
|
6165
|
+
|
6166
|
+
async def upgrade(self) -> None:
|
6167
|
+
await asyncio_subprocess_check_call('brew', 'upgrade')
|
6168
|
+
|
6169
|
+
async def install(self, *packages: SystemPackageOrStr) -> None:
|
6170
|
+
es: ta.List[str] = []
|
6171
|
+
for p in packages:
|
6172
|
+
if isinstance(p, SystemPackage):
|
6173
|
+
es.append(p.name + (f'@{p.version}' if p.version is not None else ''))
|
6174
|
+
else:
|
6175
|
+
es.append(p)
|
6176
|
+
await asyncio_subprocess_check_call('brew', 'install', *es)
|
6177
|
+
|
6178
|
+
async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
|
6179
|
+
pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
|
6180
|
+
o = await asyncio_subprocess_check_output('brew', 'info', '--json', *pns)
|
6181
|
+
j = json.loads(o.decode())
|
6182
|
+
d: ta.Dict[str, SystemPackage] = {}
|
6183
|
+
for e in j:
|
6184
|
+
if not e['installed']:
|
6185
|
+
continue
|
6186
|
+
d[e['name']] = SystemPackage(
|
6187
|
+
name=e['name'],
|
6188
|
+
version=e['installed'][0]['version'],
|
6189
|
+
)
|
6190
|
+
return d
|
6191
|
+
|
6192
|
+
|
6193
|
+
class AptSystemPackageManager(SystemPackageManager):
|
6194
|
+
_APT_ENV: ta.ClassVar[ta.Mapping[str, str]] = {
|
6195
|
+
'DEBIAN_FRONTEND': 'noninteractive',
|
6196
|
+
}
|
6197
|
+
|
6198
|
+
async def update(self) -> None:
|
6199
|
+
await asyncio_subprocess_check_call('apt', 'update', env={**os.environ, **self._APT_ENV})
|
6200
|
+
|
6201
|
+
async def upgrade(self) -> None:
|
6202
|
+
await asyncio_subprocess_check_call('apt', 'upgrade', '-y', env={**os.environ, **self._APT_ENV})
|
6203
|
+
|
6204
|
+
async def install(self, *packages: SystemPackageOrStr) -> None:
|
6205
|
+
pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
|
6206
|
+
await asyncio_subprocess_check_call('apt', 'install', '-y', *pns, env={**os.environ, **self._APT_ENV})
|
6207
|
+
|
6208
|
+
async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
|
6209
|
+
pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
|
6210
|
+
cmd = ['dpkg-query', '-W', '-f=${Package}=${Version}\n', *pns]
|
6211
|
+
stdout, stderr = await asyncio_subprocess_run(
|
6212
|
+
*cmd,
|
6213
|
+
capture_output=True,
|
6214
|
+
check=False,
|
6215
|
+
)
|
6216
|
+
d: ta.Dict[str, SystemPackage] = {}
|
6217
|
+
for l in check.not_none(stdout).decode('utf-8').strip().splitlines():
|
6218
|
+
n, v = l.split('=', 1)
|
6219
|
+
d[n] = SystemPackage(
|
6220
|
+
name=n,
|
6221
|
+
version=v,
|
6222
|
+
)
|
6223
|
+
return d
|
6224
|
+
|
6225
|
+
|
5928
6226
|
########################################
|
5929
6227
|
# ../../../omdev/interp/providers.py
|
5930
6228
|
"""
|
@@ -6078,6 +6376,50 @@ class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
|
6078
6376
|
yield rce
|
6079
6377
|
|
6080
6378
|
|
6379
|
+
##
|
6380
|
+
|
6381
|
+
|
6382
|
+
class InProcessRemoteExecutionConnector(RemoteExecutionConnector):
|
6383
|
+
def __init__(
|
6384
|
+
self,
|
6385
|
+
*,
|
6386
|
+
msh: ObjMarshalerManager,
|
6387
|
+
local_executor: LocalCommandExecutor,
|
6388
|
+
) -> None:
|
6389
|
+
super().__init__()
|
6390
|
+
|
6391
|
+
self._msh = msh
|
6392
|
+
self._local_executor = local_executor
|
6393
|
+
|
6394
|
+
@contextlib.asynccontextmanager
|
6395
|
+
async def connect(
|
6396
|
+
self,
|
6397
|
+
tgt: RemoteSpawning.Target,
|
6398
|
+
bs: MainBootstrap,
|
6399
|
+
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
6400
|
+
r0, w0 = asyncio_create_bytes_channel()
|
6401
|
+
r1, w1 = asyncio_create_bytes_channel()
|
6402
|
+
|
6403
|
+
remote_chan = RemoteChannelImpl(r0, w1, msh=self._msh)
|
6404
|
+
local_chan = RemoteChannelImpl(r1, w0, msh=self._msh)
|
6405
|
+
|
6406
|
+
rch = _RemoteCommandHandler(
|
6407
|
+
remote_chan,
|
6408
|
+
self._local_executor,
|
6409
|
+
)
|
6410
|
+
rch_task = asyncio.create_task(rch.run()) # noqa
|
6411
|
+
try:
|
6412
|
+
rce: RemoteCommandExecutor
|
6413
|
+
async with contextlib.aclosing(RemoteCommandExecutor(local_chan)) as rce:
|
6414
|
+
await rce.start()
|
6415
|
+
|
6416
|
+
yield rce
|
6417
|
+
|
6418
|
+
finally:
|
6419
|
+
rch.stop()
|
6420
|
+
await rch_task
|
6421
|
+
|
6422
|
+
|
6081
6423
|
########################################
|
6082
6424
|
# ../../../omdev/interp/pyenv.py
|
6083
6425
|
"""
|
@@ -6648,13 +6990,27 @@ def bind_remote(
|
|
6648
6990
|
|
6649
6991
|
inj.bind(SubprocessRemoteSpawning, singleton=True),
|
6650
6992
|
inj.bind(RemoteSpawning, to_key=SubprocessRemoteSpawning),
|
6651
|
-
|
6652
|
-
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
6653
|
-
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
6654
6993
|
]
|
6655
6994
|
|
6995
|
+
#
|
6996
|
+
|
6997
|
+
if remote_config.use_in_process_remote_executor:
|
6998
|
+
lst.extend([
|
6999
|
+
inj.bind(InProcessRemoteExecutionConnector, singleton=True),
|
7000
|
+
inj.bind(RemoteExecutionConnector, to_key=InProcessRemoteExecutionConnector),
|
7001
|
+
])
|
7002
|
+
else:
|
7003
|
+
lst.extend([
|
7004
|
+
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
7005
|
+
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
7006
|
+
])
|
7007
|
+
|
7008
|
+
#
|
7009
|
+
|
6656
7010
|
if (pf := remote_config.payload_file) is not None:
|
6657
|
-
lst.append(inj.bind(pf,
|
7011
|
+
lst.append(inj.bind(pf, key=RemoteExecutionPayloadFile))
|
7012
|
+
|
7013
|
+
#
|
6658
7014
|
|
6659
7015
|
return inj.as_bindings(*lst)
|
6660
7016
|
|
@@ -6776,9 +7132,6 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
6776
7132
|
opts: InterpOpts
|
6777
7133
|
|
6778
7134
|
|
6779
|
-
##
|
6780
|
-
|
6781
|
-
|
6782
7135
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
6783
7136
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
6784
7137
|
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
@@ -6906,6 +7259,48 @@ def bind_deploy(
|
|
6906
7259
|
return inj.as_bindings(*lst)
|
6907
7260
|
|
6908
7261
|
|
7262
|
+
########################################
|
7263
|
+
# ../system/inject.py
|
7264
|
+
|
7265
|
+
|
7266
|
+
def bind_system(
|
7267
|
+
*,
|
7268
|
+
system_config: SystemConfig,
|
7269
|
+
) -> InjectorBindings:
|
7270
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
7271
|
+
inj.bind(system_config),
|
7272
|
+
]
|
7273
|
+
|
7274
|
+
#
|
7275
|
+
|
7276
|
+
platform = system_config.platform or sys.platform
|
7277
|
+
lst.append(inj.bind(platform, key=SystemPlatform))
|
7278
|
+
|
7279
|
+
#
|
7280
|
+
|
7281
|
+
if platform == 'linux':
|
7282
|
+
lst.extend([
|
7283
|
+
inj.bind(AptSystemPackageManager, singleton=True),
|
7284
|
+
inj.bind(SystemPackageManager, to_key=AptSystemPackageManager),
|
7285
|
+
])
|
7286
|
+
|
7287
|
+
elif platform == 'darwin':
|
7288
|
+
lst.extend([
|
7289
|
+
inj.bind(BrewSystemPackageManager, singleton=True),
|
7290
|
+
inj.bind(SystemPackageManager, to_key=BrewSystemPackageManager),
|
7291
|
+
])
|
7292
|
+
|
7293
|
+
#
|
7294
|
+
|
7295
|
+
lst.extend([
|
7296
|
+
bind_command(CheckSystemPackageCommand, CheckSystemPackageCommandExecutor),
|
7297
|
+
])
|
7298
|
+
|
7299
|
+
#
|
7300
|
+
|
7301
|
+
return inj.as_bindings(*lst)
|
7302
|
+
|
7303
|
+
|
6909
7304
|
########################################
|
6910
7305
|
# ../inject.py
|
6911
7306
|
|
@@ -6917,6 +7312,7 @@ def bind_main(
|
|
6917
7312
|
*,
|
6918
7313
|
main_config: MainConfig,
|
6919
7314
|
remote_config: RemoteConfig,
|
7315
|
+
system_config: SystemConfig,
|
6920
7316
|
) -> InjectorBindings:
|
6921
7317
|
lst: ta.List[InjectorBindingOrBindings] = [
|
6922
7318
|
inj.bind(main_config),
|
@@ -6925,11 +7321,15 @@ def bind_main(
|
|
6925
7321
|
main_config=main_config,
|
6926
7322
|
),
|
6927
7323
|
|
7324
|
+
bind_deploy(),
|
7325
|
+
|
6928
7326
|
bind_remote(
|
6929
7327
|
remote_config=remote_config,
|
6930
7328
|
),
|
6931
7329
|
|
6932
|
-
|
7330
|
+
bind_system(
|
7331
|
+
system_config=system_config,
|
7332
|
+
),
|
6933
7333
|
]
|
6934
7334
|
|
6935
7335
|
#
|
@@ -6964,6 +7364,7 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
6964
7364
|
injector = inj.create_injector(bind_main( # noqa
|
6965
7365
|
main_config=bs.main_config,
|
6966
7366
|
remote_config=bs.remote_config,
|
7367
|
+
system_config=bs.system_config,
|
6967
7368
|
))
|
6968
7369
|
|
6969
7370
|
return injector
|
@@ -6975,7 +7376,7 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
6975
7376
|
|
6976
7377
|
class MainCli(ArgparseCli):
|
6977
7378
|
@argparse_command(
|
6978
|
-
argparse_arg('--
|
7379
|
+
argparse_arg('--_payload-file'),
|
6979
7380
|
|
6980
7381
|
argparse_arg('-s', '--shell'),
|
6981
7382
|
argparse_arg('-q', '--shell-quote', action='store_true'),
|
@@ -6993,10 +7394,7 @@ class MainCli(ArgparseCli):
|
|
6993
7394
|
|
6994
7395
|
argparse_arg('command', nargs='+'),
|
6995
7396
|
)
|
6996
|
-
def run(self) -> None:
|
6997
|
-
asyncio.run(self._async_run())
|
6998
|
-
|
6999
|
-
async def _async_run(self) -> None:
|
7397
|
+
async def run(self) -> None:
|
7000
7398
|
bs = MainBootstrap(
|
7001
7399
|
main_config=MainConfig(
|
7002
7400
|
log_level='DEBUG' if self.args.debug else 'INFO',
|
@@ -7005,7 +7403,7 @@ class MainCli(ArgparseCli):
|
|
7005
7403
|
),
|
7006
7404
|
|
7007
7405
|
remote_config=RemoteConfig(
|
7008
|
-
payload_file=self.args.
|
7406
|
+
payload_file=self.args._payload_file, # noqa
|
7009
7407
|
|
7010
7408
|
pycharm_remote_debug=PycharmRemoteDebug(
|
7011
7409
|
port=self.args.pycharm_debug_port,
|
@@ -7014,6 +7412,8 @@ class MainCli(ArgparseCli):
|
|
7014
7412
|
) if self.args.pycharm_debug_port is not None else None,
|
7015
7413
|
|
7016
7414
|
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
7415
|
+
|
7416
|
+
use_in_process_remote_executor=True,
|
7017
7417
|
),
|
7018
7418
|
)
|
7019
7419
|
|
@@ -7068,7 +7468,7 @@ class MainCli(ArgparseCli):
|
|
7068
7468
|
|
7069
7469
|
|
7070
7470
|
def _main() -> None:
|
7071
|
-
MainCli().
|
7471
|
+
sys.exit(asyncio.run(MainCli().async_cli_run()))
|
7072
7472
|
|
7073
7473
|
|
7074
7474
|
if __name__ == '__main__':
|