ominfra 0.0.0.dev152__py3-none-any.whl → 0.0.0.dev154__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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 +2 -0
- ominfra/manage/remote/_main.py +2 -2
- 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/manage.py +400 -38
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.dist-info}/RECORD +26 -20
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev152.dist-info → ominfra-0.0.0.dev154.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
|
@@ -105,6 +105,9 @@ InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
|
105
105
|
# ../../omlish/lite/subprocesses.py
|
106
106
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
107
107
|
|
108
|
+
# system/packages.py
|
109
|
+
SystemPackageOrStr = ta.Union['SystemPackage', str]
|
110
|
+
|
108
111
|
|
109
112
|
########################################
|
110
113
|
# ../../../omdev/packaging/versions.py
|
@@ -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(
|
@@ -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
|
@@ -4606,6 +4665,8 @@ class MainBootstrap:
|
|
4606
4665
|
|
4607
4666
|
remote_config: RemoteConfig = RemoteConfig()
|
4608
4667
|
|
4668
|
+
system_config: SystemConfig = SystemConfig()
|
4669
|
+
|
4609
4670
|
|
4610
4671
|
########################################
|
4611
4672
|
# ../commands/execution.py
|
@@ -4655,7 +4716,7 @@ def install_command_marshaling(
|
|
4655
4716
|
|
4656
4717
|
|
4657
4718
|
########################################
|
4658
|
-
# ../deploy/
|
4719
|
+
# ../deploy/commands.py
|
4659
4720
|
|
4660
4721
|
|
4661
4722
|
##
|
@@ -4668,9 +4729,6 @@ class DeployCommand(Command['DeployCommand.Output']):
|
|
4668
4729
|
pass
|
4669
4730
|
|
4670
4731
|
|
4671
|
-
##
|
4672
|
-
|
4673
|
-
|
4674
4732
|
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
4675
4733
|
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
4676
4734
|
log.info('Deploying!')
|
@@ -4769,6 +4827,27 @@ class RemoteChannelImpl(RemoteChannel):
|
|
4769
4827
|
return await self._recv_obj(ty)
|
4770
4828
|
|
4771
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
|
+
|
4772
4851
|
########################################
|
4773
4852
|
# ../../../omlish/lite/subprocesses.py
|
4774
4853
|
|
@@ -4955,6 +5034,10 @@ def subprocess_close(
|
|
4955
5034
|
|
4956
5035
|
########################################
|
4957
5036
|
# ../remote/execution.py
|
5037
|
+
"""
|
5038
|
+
TODO:
|
5039
|
+
- sequence all messages
|
5040
|
+
"""
|
4958
5041
|
|
4959
5042
|
|
4960
5043
|
##
|
@@ -5033,38 +5116,80 @@ class _RemoteLogHandler(logging.Handler):
|
|
5033
5116
|
|
5034
5117
|
|
5035
5118
|
class _RemoteCommandHandler:
|
5119
|
+
DEFAULT_PING_INTERVAL_S: float = 3.
|
5120
|
+
|
5036
5121
|
def __init__(
|
5037
5122
|
self,
|
5038
5123
|
chan: RemoteChannel,
|
5039
5124
|
executor: CommandExecutor,
|
5040
5125
|
*,
|
5041
5126
|
stop: ta.Optional[asyncio.Event] = None,
|
5127
|
+
ping_interval_s: float = DEFAULT_PING_INTERVAL_S,
|
5042
5128
|
) -> None:
|
5043
5129
|
super().__init__()
|
5044
5130
|
|
5045
5131
|
self._chan = chan
|
5046
5132
|
self._executor = executor
|
5047
5133
|
self._stop = stop if stop is not None else asyncio.Event()
|
5134
|
+
self._ping_interval_s = ping_interval_s
|
5048
5135
|
|
5049
5136
|
self._cmds_by_seq: ta.Dict[int, _RemoteCommandHandler._Command] = {}
|
5050
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
|
+
|
5051
5145
|
@dc.dataclass(frozen=True)
|
5052
5146
|
class _Command:
|
5053
5147
|
req: _RemoteProtocol.CommandRequest
|
5054
5148
|
fut: asyncio.Future
|
5055
5149
|
|
5056
5150
|
async def run(self) -> None:
|
5151
|
+
log.debug('_RemoteCommandHandler loop start: %r', self)
|
5152
|
+
|
5057
5153
|
stop_task = asyncio.create_task(self._stop.wait())
|
5058
5154
|
recv_task: ta.Optional[asyncio.Task] = None
|
5059
5155
|
|
5060
5156
|
while not self._stop.is_set():
|
5061
5157
|
if recv_task is None:
|
5062
|
-
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
|
+
)
|
5178
|
+
|
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)
|
5063
5191
|
|
5064
|
-
|
5065
|
-
stop_task,
|
5066
|
-
recv_task,
|
5067
|
-
], return_when=asyncio.FIRST_COMPLETED)
|
5192
|
+
#
|
5068
5193
|
|
5069
5194
|
if recv_task in done:
|
5070
5195
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -5078,6 +5203,20 @@ class _RemoteCommandHandler:
|
|
5078
5203
|
|
5079
5204
|
await self._handle_message(msg)
|
5080
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
|
+
|
5081
5220
|
async def _handle_message(self, msg: _RemoteProtocol.Message) -> None:
|
5082
5221
|
if isinstance(msg, _RemoteProtocol.PingRequest):
|
5083
5222
|
log.debug('Ping: %r', msg)
|
@@ -5085,6 +5224,12 @@ class _RemoteCommandHandler:
|
|
5085
5224
|
time=msg.time,
|
5086
5225
|
).send(self._chan)
|
5087
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
|
+
|
5088
5233
|
elif isinstance(msg, _RemoteProtocol.CommandRequest):
|
5089
5234
|
fut = asyncio.create_task(self._handle_command_request(msg))
|
5090
5235
|
self._cmds_by_seq[msg.seq] = _RemoteCommandHandler._Command(
|
@@ -5166,16 +5311,23 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5166
5311
|
if recv_task is None:
|
5167
5312
|
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
5168
5313
|
|
5169
|
-
done, pending = await asyncio.wait(
|
5170
|
-
|
5171
|
-
|
5172
|
-
|
5173
|
-
|
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
|
+
#
|
5174
5324
|
|
5175
5325
|
if queue_task in done:
|
5176
5326
|
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
5177
5327
|
queue_task = None
|
5178
|
-
await self.
|
5328
|
+
await self._handle_queued_request(req)
|
5329
|
+
|
5330
|
+
#
|
5179
5331
|
|
5180
5332
|
if recv_task in done:
|
5181
5333
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -5205,7 +5357,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5205
5357
|
|
5206
5358
|
log.debug('RemoteCommandExecutor loop exited: %r', self)
|
5207
5359
|
|
5208
|
-
async def
|
5360
|
+
async def _handle_queued_request(self, req: _Request) -> None:
|
5209
5361
|
self._reqs_by_seq[req.seq] = req
|
5210
5362
|
await _RemoteProtocol.CommandRequest(
|
5211
5363
|
seq=req.seq,
|
@@ -5219,6 +5371,10 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
5219
5371
|
time=msg.time,
|
5220
5372
|
).send(self._chan)
|
5221
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
|
+
|
5222
5378
|
elif isinstance(msg, _RemoteProtocol.LogResponse):
|
5223
5379
|
log.info(msg.s)
|
5224
5380
|
|
@@ -5435,22 +5591,25 @@ async def asyncio_subprocess_communicate(
|
|
5435
5591
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
5436
5592
|
|
5437
5593
|
|
5438
|
-
|
5439
|
-
|
5440
|
-
|
5441
|
-
async def _asyncio_subprocess_check_run(
|
5594
|
+
async def asyncio_subprocess_run(
|
5442
5595
|
*args: str,
|
5443
5596
|
input: ta.Any = None, # noqa
|
5444
5597
|
timeout: ta.Optional[float] = None,
|
5598
|
+
check: bool = False, # noqa
|
5599
|
+
capture_output: ta.Optional[bool] = None,
|
5445
5600
|
**kwargs: ta.Any,
|
5446
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
|
+
|
5447
5606
|
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
5448
5607
|
|
5449
5608
|
proc: asyncio.subprocess.Process
|
5450
5609
|
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
5451
5610
|
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
5452
5611
|
|
5453
|
-
if proc.returncode:
|
5612
|
+
if check and proc.returncode:
|
5454
5613
|
raise subprocess.CalledProcessError(
|
5455
5614
|
proc.returncode,
|
5456
5615
|
args,
|
@@ -5461,6 +5620,9 @@ async def _asyncio_subprocess_check_run(
|
|
5461
5620
|
return stdout, stderr
|
5462
5621
|
|
5463
5622
|
|
5623
|
+
##
|
5624
|
+
|
5625
|
+
|
5464
5626
|
async def asyncio_subprocess_check_call(
|
5465
5627
|
*args: str,
|
5466
5628
|
stdout: ta.Any = sys.stderr,
|
@@ -5468,11 +5630,12 @@ async def asyncio_subprocess_check_call(
|
|
5468
5630
|
timeout: ta.Optional[float] = None,
|
5469
5631
|
**kwargs: ta.Any,
|
5470
5632
|
) -> None:
|
5471
|
-
_, _ = await
|
5633
|
+
_, _ = await asyncio_subprocess_run(
|
5472
5634
|
*args,
|
5473
5635
|
stdout=stdout,
|
5474
5636
|
input=input,
|
5475
5637
|
timeout=timeout,
|
5638
|
+
check=True,
|
5476
5639
|
**kwargs,
|
5477
5640
|
)
|
5478
5641
|
|
@@ -5483,11 +5646,12 @@ async def asyncio_subprocess_check_output(
|
|
5483
5646
|
timeout: ta.Optional[float] = None,
|
5484
5647
|
**kwargs: ta.Any,
|
5485
5648
|
) -> bytes:
|
5486
|
-
stdout, stderr = await
|
5649
|
+
stdout, stderr = await asyncio_subprocess_run(
|
5487
5650
|
*args,
|
5488
5651
|
stdout=asyncio.subprocess.PIPE,
|
5489
5652
|
input=input,
|
5490
5653
|
timeout=timeout,
|
5654
|
+
check=True,
|
5491
5655
|
**kwargs,
|
5492
5656
|
)
|
5493
5657
|
|
@@ -5682,9 +5846,6 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
5682
5846
|
stderr: ta.Optional[bytes] = None
|
5683
5847
|
|
5684
5848
|
|
5685
|
-
##
|
5686
|
-
|
5687
|
-
|
5688
5849
|
class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
|
5689
5850
|
async def execute(self, cmd: SubprocessCommand) -> SubprocessCommand.Output:
|
5690
5851
|
proc: asyncio.subprocess.Process
|
@@ -5966,6 +6127,102 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
5966
6127
|
pass
|
5967
6128
|
|
5968
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
|
+
|
5969
6226
|
########################################
|
5970
6227
|
# ../../../omdev/interp/providers.py
|
5971
6228
|
"""
|
@@ -6119,6 +6376,50 @@ class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
|
6119
6376
|
yield rce
|
6120
6377
|
|
6121
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
|
+
|
6122
6423
|
########################################
|
6123
6424
|
# ../../../omdev/interp/pyenv.py
|
6124
6425
|
"""
|
@@ -6689,13 +6990,27 @@ def bind_remote(
|
|
6689
6990
|
|
6690
6991
|
inj.bind(SubprocessRemoteSpawning, singleton=True),
|
6691
6992
|
inj.bind(RemoteSpawning, to_key=SubprocessRemoteSpawning),
|
6692
|
-
|
6693
|
-
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
6694
|
-
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
6695
6993
|
]
|
6696
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
|
+
|
6697
7010
|
if (pf := remote_config.payload_file) is not None:
|
6698
|
-
lst.append(inj.bind(pf,
|
7011
|
+
lst.append(inj.bind(pf, key=RemoteExecutionPayloadFile))
|
7012
|
+
|
7013
|
+
#
|
6699
7014
|
|
6700
7015
|
return inj.as_bindings(*lst)
|
6701
7016
|
|
@@ -6817,9 +7132,6 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
6817
7132
|
opts: InterpOpts
|
6818
7133
|
|
6819
7134
|
|
6820
|
-
##
|
6821
|
-
|
6822
|
-
|
6823
7135
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
6824
7136
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
6825
7137
|
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
@@ -6947,6 +7259,48 @@ def bind_deploy(
|
|
6947
7259
|
return inj.as_bindings(*lst)
|
6948
7260
|
|
6949
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
|
+
|
6950
7304
|
########################################
|
6951
7305
|
# ../inject.py
|
6952
7306
|
|
@@ -6958,6 +7312,7 @@ def bind_main(
|
|
6958
7312
|
*,
|
6959
7313
|
main_config: MainConfig,
|
6960
7314
|
remote_config: RemoteConfig,
|
7315
|
+
system_config: SystemConfig,
|
6961
7316
|
) -> InjectorBindings:
|
6962
7317
|
lst: ta.List[InjectorBindingOrBindings] = [
|
6963
7318
|
inj.bind(main_config),
|
@@ -6966,11 +7321,15 @@ def bind_main(
|
|
6966
7321
|
main_config=main_config,
|
6967
7322
|
),
|
6968
7323
|
|
7324
|
+
bind_deploy(),
|
7325
|
+
|
6969
7326
|
bind_remote(
|
6970
7327
|
remote_config=remote_config,
|
6971
7328
|
),
|
6972
7329
|
|
6973
|
-
|
7330
|
+
bind_system(
|
7331
|
+
system_config=system_config,
|
7332
|
+
),
|
6974
7333
|
]
|
6975
7334
|
|
6976
7335
|
#
|
@@ -7005,6 +7364,7 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
7005
7364
|
injector = inj.create_injector(bind_main( # noqa
|
7006
7365
|
main_config=bs.main_config,
|
7007
7366
|
remote_config=bs.remote_config,
|
7367
|
+
system_config=bs.system_config,
|
7008
7368
|
))
|
7009
7369
|
|
7010
7370
|
return injector
|
@@ -7052,6 +7412,8 @@ class MainCli(ArgparseCli):
|
|
7052
7412
|
) if self.args.pycharm_debug_port is not None else None,
|
7053
7413
|
|
7054
7414
|
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
7415
|
+
|
7416
|
+
use_in_process_remote_executor=True,
|
7055
7417
|
),
|
7056
7418
|
)
|
7057
7419
|
|