ominfra 0.0.0.dev136__py3-none-any.whl → 0.0.0.dev138__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/new/_manage.py +293 -174
- ominfra/manage/new/main.py +103 -31
- ominfra/pyremote.py +196 -145
- ominfra/scripts/supervisor.py +32 -31
- ominfra/supervisor/processimpl.py +32 -31
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/RECORD +11 -11
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev136.dist-info → ominfra-0.0.0.dev138.dist-info}/top_level.txt +0 -0
ominfra/manage/new/_manage.py
CHANGED
@@ -4,6 +4,10 @@
|
|
4
4
|
# @omlish-script
|
5
5
|
# @omlish-amalg-output main.py
|
6
6
|
# ruff: noqa: N802 UP006 UP007 UP036
|
7
|
+
"""
|
8
|
+
manage.py -s 'docker run -i python:3.12'
|
9
|
+
manage.py -qs 'ssh -i foo/bar foo@bar.baz' --python=python3.8
|
10
|
+
"""
|
7
11
|
import abc
|
8
12
|
import base64
|
9
13
|
import collections.abc
|
@@ -25,7 +29,6 @@ import site
|
|
25
29
|
import struct
|
26
30
|
import subprocess
|
27
31
|
import sys
|
28
|
-
import textwrap
|
29
32
|
import threading
|
30
33
|
import time
|
31
34
|
import types
|
@@ -87,11 +90,120 @@ Basically this: https://mitogen.networkgenomics.com/howitworks.html
|
|
87
90
|
##
|
88
91
|
|
89
92
|
|
93
|
+
@dc.dataclass(frozen=True)
|
94
|
+
class PyremoteBootstrapOptions:
|
95
|
+
debug: bool = False
|
96
|
+
|
97
|
+
|
98
|
+
##
|
99
|
+
|
100
|
+
|
101
|
+
@dc.dataclass(frozen=True)
|
102
|
+
class PyremoteEnvInfo:
|
103
|
+
sys_base_prefix: str
|
104
|
+
sys_byteorder: str
|
105
|
+
sys_defaultencoding: str
|
106
|
+
sys_exec_prefix: str
|
107
|
+
sys_executable: str
|
108
|
+
sys_implementation_name: str
|
109
|
+
sys_path: ta.List[str]
|
110
|
+
sys_platform: str
|
111
|
+
sys_prefix: str
|
112
|
+
sys_version: str
|
113
|
+
sys_version_info: ta.List[ta.Union[int, str]]
|
114
|
+
|
115
|
+
platform_architecture: ta.List[str]
|
116
|
+
platform_machine: str
|
117
|
+
platform_platform: str
|
118
|
+
platform_processor: str
|
119
|
+
platform_system: str
|
120
|
+
platform_release: str
|
121
|
+
platform_version: str
|
122
|
+
|
123
|
+
site_userbase: str
|
124
|
+
|
125
|
+
os_cwd: str
|
126
|
+
os_gid: int
|
127
|
+
os_loadavg: ta.List[float]
|
128
|
+
os_login: ta.Optional[str]
|
129
|
+
os_pgrp: int
|
130
|
+
os_pid: int
|
131
|
+
os_ppid: int
|
132
|
+
os_uid: int
|
133
|
+
|
134
|
+
pw_name: str
|
135
|
+
pw_uid: int
|
136
|
+
pw_gid: int
|
137
|
+
pw_gecos: str
|
138
|
+
pw_dir: str
|
139
|
+
pw_shell: str
|
140
|
+
|
141
|
+
env_path: ta.Optional[str]
|
142
|
+
|
143
|
+
|
144
|
+
def _get_pyremote_env_info() -> PyremoteEnvInfo:
|
145
|
+
os_uid = os.getuid()
|
146
|
+
|
147
|
+
pw = pwd.getpwuid(os_uid)
|
148
|
+
|
149
|
+
os_login: ta.Optional[str]
|
150
|
+
try:
|
151
|
+
os_login = os.getlogin()
|
152
|
+
except OSError:
|
153
|
+
os_login = None
|
154
|
+
|
155
|
+
return PyremoteEnvInfo(
|
156
|
+
sys_base_prefix=sys.base_prefix,
|
157
|
+
sys_byteorder=sys.byteorder,
|
158
|
+
sys_defaultencoding=sys.getdefaultencoding(),
|
159
|
+
sys_exec_prefix=sys.exec_prefix,
|
160
|
+
sys_executable=sys.executable,
|
161
|
+
sys_implementation_name=sys.implementation.name,
|
162
|
+
sys_path=sys.path,
|
163
|
+
sys_platform=sys.platform,
|
164
|
+
sys_prefix=sys.prefix,
|
165
|
+
sys_version=sys.version,
|
166
|
+
sys_version_info=list(sys.version_info),
|
167
|
+
|
168
|
+
platform_architecture=list(platform.architecture()),
|
169
|
+
platform_machine=platform.machine(),
|
170
|
+
platform_platform=platform.platform(),
|
171
|
+
platform_processor=platform.processor(),
|
172
|
+
platform_system=platform.system(),
|
173
|
+
platform_release=platform.release(),
|
174
|
+
platform_version=platform.version(),
|
175
|
+
|
176
|
+
site_userbase=site.getuserbase(),
|
177
|
+
|
178
|
+
os_cwd=os.getcwd(),
|
179
|
+
os_gid=os.getgid(),
|
180
|
+
os_loadavg=list(os.getloadavg()),
|
181
|
+
os_login=os_login,
|
182
|
+
os_pgrp=os.getpgrp(),
|
183
|
+
os_pid=os.getpid(),
|
184
|
+
os_ppid=os.getppid(),
|
185
|
+
os_uid=os_uid,
|
186
|
+
|
187
|
+
pw_name=pw.pw_name,
|
188
|
+
pw_uid=pw.pw_uid,
|
189
|
+
pw_gid=pw.pw_gid,
|
190
|
+
pw_gecos=pw.pw_gecos,
|
191
|
+
pw_dir=pw.pw_dir,
|
192
|
+
pw_shell=pw.pw_shell,
|
193
|
+
|
194
|
+
env_path=os.environ.get('PATH'),
|
195
|
+
)
|
196
|
+
|
197
|
+
|
198
|
+
##
|
199
|
+
|
200
|
+
|
90
201
|
_PYREMOTE_BOOTSTRAP_INPUT_FD = 100
|
91
202
|
_PYREMOTE_BOOTSTRAP_SRC_FD = 101
|
92
203
|
|
93
204
|
_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR = '_OPYR_CHILD_PID'
|
94
205
|
_PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
|
206
|
+
_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR = '_OPYR_OPTIONS_JSON'
|
95
207
|
|
96
208
|
_PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
|
97
209
|
_PYREMOTE_BOOTSTRAP_ACK1 = b'OPYR001\n'
|
@@ -153,7 +265,9 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
|
|
153
265
|
|
154
266
|
# Read main src from stdin
|
155
267
|
main_z_len = struct.unpack('<I', os.read(0, 4))[0]
|
156
|
-
|
268
|
+
if len(main_z := os.fdopen(0, 'rb').read(main_z_len)) != main_z_len:
|
269
|
+
raise EOFError
|
270
|
+
main_src = zlib.decompress(main_z)
|
157
271
|
|
158
272
|
# Write both copies of main src. Must write to w0 (parent stdin) before w1 (copy pipe) as pipe will likely fill
|
159
273
|
# and block and need to be drained by pyremote_bootstrap_finalize running in parent.
|
@@ -176,6 +290,8 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
176
290
|
if any(c in context_name for c in '\'"'):
|
177
291
|
raise NameError(context_name)
|
178
292
|
|
293
|
+
import inspect
|
294
|
+
import textwrap
|
179
295
|
bs_src = textwrap.dedent(inspect.getsource(_pyremote_bootstrap_main))
|
180
296
|
|
181
297
|
for gl in [
|
@@ -202,9 +318,6 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
202
318
|
bs_z = zlib.compress(bs_src.encode('utf-8'))
|
203
319
|
bs_z64 = base64.encodebytes(bs_z).replace(b'\n', b'')
|
204
320
|
|
205
|
-
def dq_repr(o: ta.Any) -> str:
|
206
|
-
return '"' + repr(o)[1:-1] + '"'
|
207
|
-
|
208
321
|
stmts = [
|
209
322
|
f'import {", ".join(_PYREMOTE_BOOTSTRAP_IMPORTS)}',
|
210
323
|
f'exec(zlib.decompress(base64.decodebytes({bs_z64!r})))',
|
@@ -219,99 +332,83 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
219
332
|
|
220
333
|
|
221
334
|
@dc.dataclass(frozen=True)
|
222
|
-
class
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
sys_implementation_name: str
|
229
|
-
sys_path: ta.List[str]
|
230
|
-
sys_platform: str
|
231
|
-
sys_prefix: str
|
232
|
-
sys_version: str
|
233
|
-
sys_version_info: ta.List[ta.Union[int, str]]
|
234
|
-
|
235
|
-
platform_architecture: ta.List[str]
|
236
|
-
platform_machine: str
|
237
|
-
platform_platform: str
|
238
|
-
platform_processor: str
|
239
|
-
platform_system: str
|
240
|
-
platform_release: str
|
241
|
-
platform_version: str
|
242
|
-
|
243
|
-
site_userbase: str
|
244
|
-
|
245
|
-
os_cwd: str
|
246
|
-
os_gid: int
|
247
|
-
os_loadavg: ta.List[float]
|
248
|
-
os_login: ta.Optional[str]
|
249
|
-
os_pgrp: int
|
250
|
-
os_pid: int
|
251
|
-
os_ppid: int
|
252
|
-
os_uid: int
|
253
|
-
|
254
|
-
pw_name: str
|
255
|
-
pw_uid: int
|
256
|
-
pw_gid: int
|
257
|
-
pw_gecos: str
|
258
|
-
pw_dir: str
|
259
|
-
pw_shell: str
|
260
|
-
|
261
|
-
env_path: ta.Optional[str]
|
335
|
+
class PyremotePayloadRuntime:
|
336
|
+
input: ta.BinaryIO
|
337
|
+
output: ta.BinaryIO
|
338
|
+
main_src: str
|
339
|
+
options: PyremoteBootstrapOptions
|
340
|
+
env_info: PyremoteEnvInfo
|
262
341
|
|
263
342
|
|
264
|
-
def
|
265
|
-
|
343
|
+
def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
344
|
+
# If json options var is not present we need to do initial finalization
|
345
|
+
if _PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR not in os.environ:
|
346
|
+
# Read second copy of main src
|
347
|
+
r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
|
348
|
+
main_src = r1.read().decode('utf-8')
|
349
|
+
r1.close()
|
350
|
+
|
351
|
+
# Reap boostrap child. Must be done after reading second copy of source because source may be too big to fit in
|
352
|
+
# a pipe at once.
|
353
|
+
os.waitpid(int(os.environ.pop(_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR)), 0)
|
354
|
+
|
355
|
+
# Read options
|
356
|
+
options_json_len = struct.unpack('<I', os.read(_PYREMOTE_BOOTSTRAP_INPUT_FD, 4))[0]
|
357
|
+
if len(options_json := os.read(_PYREMOTE_BOOTSTRAP_INPUT_FD, options_json_len)) != options_json_len:
|
358
|
+
raise EOFError
|
359
|
+
options = PyremoteBootstrapOptions(**json.loads(options_json.decode('utf-8')))
|
360
|
+
|
361
|
+
# If debugging, re-exec as file
|
362
|
+
if options.debug:
|
363
|
+
# Write temp source file
|
364
|
+
import tempfile
|
365
|
+
tfd, tfn = tempfile.mkstemp('-pyremote.py')
|
366
|
+
os.write(tfd, main_src.encode('utf-8'))
|
367
|
+
os.close(tfd)
|
368
|
+
|
369
|
+
# Set json options var
|
370
|
+
os.environ[_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR] = options_json.decode('utf-8')
|
371
|
+
|
372
|
+
# Re-exec temp file
|
373
|
+
os.execl(os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR], sys.orig_argv[0], tfn)
|
266
374
|
|
267
|
-
|
375
|
+
else:
|
376
|
+
# Load options json var
|
377
|
+
options_json_str = os.environ.pop(_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR)
|
378
|
+
options = PyremoteBootstrapOptions(**json.loads(options_json_str))
|
268
379
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
except OSError:
|
273
|
-
os_login = None
|
380
|
+
# Read temp source file
|
381
|
+
with open(sys.orig_argv[1]) as sf:
|
382
|
+
main_src = sf.read()
|
274
383
|
|
275
|
-
|
276
|
-
|
277
|
-
sys_byteorder=sys.byteorder,
|
278
|
-
sys_defaultencoding=sys.getdefaultencoding(),
|
279
|
-
sys_exec_prefix=sys.exec_prefix,
|
280
|
-
sys_executable=sys.executable,
|
281
|
-
sys_implementation_name=sys.implementation.name,
|
282
|
-
sys_path=sys.path,
|
283
|
-
sys_platform=sys.platform,
|
284
|
-
sys_prefix=sys.prefix,
|
285
|
-
sys_version=sys.version,
|
286
|
-
sys_version_info=list(sys.version_info),
|
384
|
+
# Restore original argv0
|
385
|
+
sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
|
287
386
|
|
288
|
-
|
289
|
-
|
290
|
-
platform_platform=platform.platform(),
|
291
|
-
platform_processor=platform.processor(),
|
292
|
-
platform_system=platform.system(),
|
293
|
-
platform_release=platform.release(),
|
294
|
-
platform_version=platform.version(),
|
387
|
+
# Write third ack
|
388
|
+
os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
|
295
389
|
|
296
|
-
|
390
|
+
# Write env info
|
391
|
+
env_info = _get_pyremote_env_info()
|
392
|
+
env_info_json = json.dumps(dc.asdict(env_info), indent=None, separators=(',', ':')) # noqa
|
393
|
+
os.write(1, struct.pack('<I', len(env_info_json)))
|
394
|
+
os.write(1, env_info_json.encode('utf-8'))
|
297
395
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
os_pid=os.getpid(),
|
304
|
-
os_ppid=os.getppid(),
|
305
|
-
os_uid=os_uid,
|
396
|
+
# Setup IO
|
397
|
+
input = os.fdopen(_PYREMOTE_BOOTSTRAP_INPUT_FD, 'rb', 0) # noqa
|
398
|
+
output = os.fdopen(os.dup(1), 'wb', 0) # noqa
|
399
|
+
os.dup2(nfd := os.open('/dev/null', os.O_WRONLY), 1)
|
400
|
+
os.close(nfd)
|
306
401
|
|
307
|
-
|
308
|
-
|
309
|
-
pw_gid=pw.pw_gid,
|
310
|
-
pw_gecos=pw.pw_gecos,
|
311
|
-
pw_dir=pw.pw_dir,
|
312
|
-
pw_shell=pw.pw_shell,
|
402
|
+
# Write fourth ack
|
403
|
+
output.write(_PYREMOTE_BOOTSTRAP_ACK3)
|
313
404
|
|
314
|
-
|
405
|
+
# Return
|
406
|
+
return PyremotePayloadRuntime(
|
407
|
+
input=input,
|
408
|
+
output=output,
|
409
|
+
main_src=main_src,
|
410
|
+
options=options,
|
411
|
+
env_info=env_info,
|
315
412
|
)
|
316
413
|
|
317
414
|
|
@@ -319,12 +416,15 @@ def _get_pyremote_env_info() -> PyremoteEnvInfo:
|
|
319
416
|
|
320
417
|
|
321
418
|
class PyremoteBootstrapDriver:
|
322
|
-
def __init__(self, main_src: str) -> None:
|
419
|
+
def __init__(self, main_src: str, options: PyremoteBootstrapOptions = PyremoteBootstrapOptions()) -> None:
|
323
420
|
super().__init__()
|
324
421
|
|
325
422
|
self._main_src = main_src
|
326
423
|
self._main_z = zlib.compress(main_src.encode('utf-8'))
|
327
424
|
|
425
|
+
self._options = options
|
426
|
+
self._options_json = json.dumps(dc.asdict(options), indent=None, separators=(',', ':')).encode('utf-8') # noqa
|
427
|
+
|
328
428
|
#
|
329
429
|
|
330
430
|
@dc.dataclass(frozen=True)
|
@@ -344,7 +444,7 @@ class PyremoteBootstrapDriver:
|
|
344
444
|
env_info: PyremoteEnvInfo
|
345
445
|
|
346
446
|
def gen(self) -> ta.Generator[ta.Union[Read, Write], ta.Optional[bytes], Result]:
|
347
|
-
# Read first ack
|
447
|
+
# Read first ack (after fork)
|
348
448
|
yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK0)
|
349
449
|
|
350
450
|
# Read pid
|
@@ -355,8 +455,14 @@ class PyremoteBootstrapDriver:
|
|
355
455
|
yield from self._write(struct.pack('<I', len(self._main_z)))
|
356
456
|
yield from self._write(self._main_z)
|
357
457
|
|
358
|
-
# Read second
|
458
|
+
# Read second ack (after writing src copies)
|
359
459
|
yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK1)
|
460
|
+
|
461
|
+
# Write options
|
462
|
+
yield from self._write(struct.pack('<I', len(self._options_json)))
|
463
|
+
yield from self._write(self._options_json)
|
464
|
+
|
465
|
+
# Read third ack (after reaping child process)
|
360
466
|
yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK2)
|
361
467
|
|
362
468
|
# Read env info
|
@@ -366,7 +472,7 @@ class PyremoteBootstrapDriver:
|
|
366
472
|
env_info_json = d.decode('utf-8')
|
367
473
|
env_info = PyremoteEnvInfo(**json.loads(env_info_json))
|
368
474
|
|
369
|
-
# Read fourth ack
|
475
|
+
# Read fourth ack (after finalization completed)
|
370
476
|
yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK3)
|
371
477
|
|
372
478
|
# Return
|
@@ -409,7 +515,8 @@ class PyremoteBootstrapDriver:
|
|
409
515
|
return e.value
|
410
516
|
|
411
517
|
if isinstance(go, self.Read):
|
412
|
-
gi
|
518
|
+
if len(gi := stdout.read(go.sz)) != go.sz:
|
519
|
+
raise EOFError
|
413
520
|
elif isinstance(go, self.Write):
|
414
521
|
gi = None
|
415
522
|
stdin.write(go.d)
|
@@ -418,57 +525,6 @@ class PyremoteBootstrapDriver:
|
|
418
525
|
raise TypeError(go)
|
419
526
|
|
420
527
|
|
421
|
-
##
|
422
|
-
|
423
|
-
|
424
|
-
@dc.dataclass(frozen=True)
|
425
|
-
class PyremotePayloadRuntime:
|
426
|
-
input: ta.BinaryIO
|
427
|
-
output: ta.BinaryIO
|
428
|
-
main_src: str
|
429
|
-
env_info: PyremoteEnvInfo
|
430
|
-
|
431
|
-
|
432
|
-
def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
433
|
-
# Restore original argv0
|
434
|
-
sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
|
435
|
-
|
436
|
-
# Read second copy of main src
|
437
|
-
r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
|
438
|
-
main_src = r1.read().decode('utf-8')
|
439
|
-
r1.close()
|
440
|
-
|
441
|
-
# Reap boostrap child. Must be done after reading second copy of source because source may be too big to fit in a
|
442
|
-
# pipe at once.
|
443
|
-
os.waitpid(int(os.environ.pop(_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR)), 0)
|
444
|
-
|
445
|
-
# Write third ack
|
446
|
-
os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
|
447
|
-
|
448
|
-
# Write env info
|
449
|
-
env_info = _get_pyremote_env_info()
|
450
|
-
env_info_json = json.dumps(dc.asdict(env_info), indent=None, separators=(',', ':')) # noqa
|
451
|
-
os.write(1, struct.pack('<I', len(env_info_json)))
|
452
|
-
os.write(1, env_info_json.encode('utf-8'))
|
453
|
-
|
454
|
-
# Setup IO
|
455
|
-
input = os.fdopen(_PYREMOTE_BOOTSTRAP_INPUT_FD, 'rb', 0) # noqa
|
456
|
-
output = os.fdopen(os.dup(1), 'wb', 0) # noqa
|
457
|
-
os.dup2(nfd := os.open('/dev/null', os.O_WRONLY), 1)
|
458
|
-
os.close(nfd)
|
459
|
-
|
460
|
-
# Write fourth ack
|
461
|
-
output.write(_PYREMOTE_BOOTSTRAP_ACK3)
|
462
|
-
|
463
|
-
# Return
|
464
|
-
return PyremotePayloadRuntime(
|
465
|
-
input=input,
|
466
|
-
output=output,
|
467
|
-
main_src=main_src,
|
468
|
-
env_info=env_info,
|
469
|
-
)
|
470
|
-
|
471
|
-
|
472
528
|
########################################
|
473
529
|
# ../../../../omlish/lite/cached.py
|
474
530
|
|
@@ -1509,8 +1565,41 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
|
|
1509
1565
|
##
|
1510
1566
|
|
1511
1567
|
|
1512
|
-
|
1513
|
-
|
1568
|
+
_COMMAND_TYPES = {
|
1569
|
+
'subprocess': SubprocessCommand,
|
1570
|
+
}
|
1571
|
+
|
1572
|
+
|
1573
|
+
register_opj_marshaler(
|
1574
|
+
Command.Input,
|
1575
|
+
PolymorphicObjMarshaler.of([
|
1576
|
+
PolymorphicObjMarshaler.Impl(
|
1577
|
+
cty.Input,
|
1578
|
+
k,
|
1579
|
+
get_obj_marshaler(cty.Input),
|
1580
|
+
)
|
1581
|
+
for k, cty in _COMMAND_TYPES.items()
|
1582
|
+
]),
|
1583
|
+
)
|
1584
|
+
|
1585
|
+
register_opj_marshaler(
|
1586
|
+
Command.Output,
|
1587
|
+
PolymorphicObjMarshaler.of([
|
1588
|
+
PolymorphicObjMarshaler.Impl(
|
1589
|
+
cty.Output,
|
1590
|
+
k,
|
1591
|
+
get_obj_marshaler(cty.Output),
|
1592
|
+
)
|
1593
|
+
for k, cty in _COMMAND_TYPES.items()
|
1594
|
+
]),
|
1595
|
+
)
|
1596
|
+
|
1597
|
+
|
1598
|
+
##
|
1599
|
+
|
1600
|
+
|
1601
|
+
def _send_obj(f: ta.IO, o: ta.Any, ty: ta.Any = None) -> None:
|
1602
|
+
j = json_dumps_compact(marshal_obj(o, ty))
|
1514
1603
|
d = j.encode('utf-8')
|
1515
1604
|
|
1516
1605
|
f.write(struct.pack('<I', len(d)))
|
@@ -1518,33 +1607,74 @@ def _send_obj(f: ta.IO, o: ta.Any) -> None:
|
|
1518
1607
|
f.flush()
|
1519
1608
|
|
1520
1609
|
|
1521
|
-
def _recv_obj(f: ta.IO, ty:
|
1610
|
+
def _recv_obj(f: ta.IO, ty: ta.Any) -> ta.Any:
|
1522
1611
|
d = f.read(4)
|
1523
1612
|
if not d:
|
1524
1613
|
return None
|
1525
1614
|
if len(d) != 4:
|
1526
|
-
raise
|
1615
|
+
raise EOFError
|
1527
1616
|
|
1528
1617
|
sz = struct.unpack('<I', d)[0]
|
1529
1618
|
d = f.read(sz)
|
1530
|
-
if
|
1531
|
-
raise
|
1619
|
+
if len(d) != sz:
|
1620
|
+
raise EOFError
|
1532
1621
|
|
1533
1622
|
j = json.loads(d.decode('utf-8'))
|
1534
1623
|
return unmarshal_obj(j, ty)
|
1535
1624
|
|
1536
1625
|
|
1626
|
+
##
|
1627
|
+
|
1628
|
+
|
1537
1629
|
def _remote_main() -> None:
|
1538
1630
|
rt = pyremote_bootstrap_finalize() # noqa
|
1539
1631
|
|
1540
1632
|
while True:
|
1541
|
-
i = _recv_obj(rt.input,
|
1633
|
+
i = _recv_obj(rt.input, Command.Input)
|
1542
1634
|
if i is None:
|
1543
1635
|
break
|
1544
1636
|
|
1545
|
-
|
1637
|
+
if isinstance(i, SubprocessCommand.Input):
|
1638
|
+
o = SubprocessCommand()._execute(i) # noqa
|
1639
|
+
else:
|
1640
|
+
raise TypeError(i)
|
1641
|
+
|
1642
|
+
_send_obj(rt.output, o, Command.Output)
|
1643
|
+
|
1644
|
+
|
1645
|
+
##
|
1646
|
+
|
1546
1647
|
|
1547
|
-
|
1648
|
+
@cached_nullary
|
1649
|
+
def _get_self_src() -> str:
|
1650
|
+
return inspect.getsource(sys.modules[__name__])
|
1651
|
+
|
1652
|
+
|
1653
|
+
def _is_src_amalg(src: str) -> bool:
|
1654
|
+
for l in src.splitlines(): # noqa
|
1655
|
+
if l.startswith('# @omlish-amalg-output '):
|
1656
|
+
return True
|
1657
|
+
return False
|
1658
|
+
|
1659
|
+
|
1660
|
+
@cached_nullary
|
1661
|
+
def _is_self_amalg() -> bool:
|
1662
|
+
return _is_src_amalg(_get_self_src())
|
1663
|
+
|
1664
|
+
|
1665
|
+
def _get_amalg_src(*, amalg_file: ta.Optional[str]) -> str:
|
1666
|
+
if amalg_file is not None:
|
1667
|
+
with open(amalg_file) as f:
|
1668
|
+
return f.read()
|
1669
|
+
|
1670
|
+
if _is_self_amalg():
|
1671
|
+
return _get_self_src()
|
1672
|
+
|
1673
|
+
import importlib.resources
|
1674
|
+
return importlib.resources.read_text(__package__, '_manage.py')
|
1675
|
+
|
1676
|
+
|
1677
|
+
##
|
1548
1678
|
|
1549
1679
|
|
1550
1680
|
def _main() -> None:
|
@@ -1561,23 +1691,7 @@ def _main() -> None:
|
|
1561
1691
|
|
1562
1692
|
#
|
1563
1693
|
|
1564
|
-
|
1565
|
-
self_src_lines = self_src.splitlines()
|
1566
|
-
for l in self_src_lines:
|
1567
|
-
if l.startswith('# @omlish-amalg-output '):
|
1568
|
-
is_self_amalg = True
|
1569
|
-
break
|
1570
|
-
else:
|
1571
|
-
is_self_amalg = False
|
1572
|
-
|
1573
|
-
if is_self_amalg:
|
1574
|
-
amalg_src = self_src
|
1575
|
-
else:
|
1576
|
-
amalg_file = args._amalg_file # noqa
|
1577
|
-
if amalg_file is None:
|
1578
|
-
amalg_file = os.path.join(os.path.dirname(__file__), '_manage.py')
|
1579
|
-
with open(amalg_file) as f:
|
1580
|
-
amalg_src = f.read()
|
1694
|
+
amalg_src = _get_amalg_src(amalg_file=args._amalg_file) # noqa
|
1581
1695
|
|
1582
1696
|
#
|
1583
1697
|
|
@@ -1612,8 +1726,13 @@ def _main() -> None:
|
|
1612
1726
|
stdin = check_not_none(proc.stdin)
|
1613
1727
|
stdout = check_not_none(proc.stdout)
|
1614
1728
|
|
1615
|
-
res = PyremoteBootstrapDriver(
|
1616
|
-
|
1729
|
+
res = PyremoteBootstrapDriver( # noqa
|
1730
|
+
remote_src,
|
1731
|
+
PyremoteBootstrapOptions(
|
1732
|
+
# debug=True,
|
1733
|
+
),
|
1734
|
+
).run(stdin, stdout)
|
1735
|
+
# print(res)
|
1617
1736
|
|
1618
1737
|
#
|
1619
1738
|
|
@@ -1628,9 +1747,9 @@ def _main() -> None:
|
|
1628
1747
|
capture_stdout=True,
|
1629
1748
|
),
|
1630
1749
|
]:
|
1631
|
-
_send_obj(stdin, ci)
|
1750
|
+
_send_obj(stdin, ci, Command.Input)
|
1632
1751
|
|
1633
|
-
o = _recv_obj(stdout,
|
1752
|
+
o = _recv_obj(stdout, Command.Output)
|
1634
1753
|
|
1635
1754
|
print(o)
|
1636
1755
|
|