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/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/lite/asyncio/asyncio.py
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/lite/asyncio/asyncio.py
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/command.py
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.Request.recv(self._chan))
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
- done, pending = await asyncio.wait([
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
- stop_task,
5171
- queue_task,
5172
- recv_task,
5173
- ], return_when=asyncio.FIRST_COMPLETED)
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._handle_request(req)
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 _handle_request(self, req: _Request) -> None:
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 _asyncio_subprocess_check_run(
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 _asyncio_subprocess_check_run(
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, to_key=RemoteExecutionPayloadFile))
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
- bind_deploy(),
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