ominfra 0.0.0.dev152__py3-none-any.whl → 0.0.0.dev154__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/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
|
|