ominfra 0.0.0.dev138__py3-none-any.whl → 0.0.0.dev140__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.
Files changed (47) hide show
  1. ominfra/manage/__init__.py +13 -0
  2. ominfra/manage/{new/commands → commands}/base.py +9 -7
  3. ominfra/manage/{new/commands → commands}/subprocess.py +20 -15
  4. ominfra/manage/main.py +175 -0
  5. ominfra/manage/payload.py +35 -0
  6. ominfra/manage/spawning.py +100 -0
  7. ominfra/pyremote.py +18 -8
  8. ominfra/scripts/journald2aws.py +7 -0
  9. ominfra/{manage/new/_manage.py → scripts/manage.py} +248 -153
  10. ominfra/scripts/supervisor.py +7 -0
  11. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/METADATA +3 -3
  12. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/RECORD +17 -44
  13. ominfra/manage/deploy/_executor.py +0 -1415
  14. ominfra/manage/deploy/configs.py +0 -19
  15. ominfra/manage/deploy/executor/__init__.py +0 -1
  16. ominfra/manage/deploy/executor/base.py +0 -115
  17. ominfra/manage/deploy/executor/concerns/__init__.py +0 -0
  18. ominfra/manage/deploy/executor/concerns/dirs.py +0 -28
  19. ominfra/manage/deploy/executor/concerns/nginx.py +0 -47
  20. ominfra/manage/deploy/executor/concerns/repo.py +0 -17
  21. ominfra/manage/deploy/executor/concerns/supervisor.py +0 -46
  22. ominfra/manage/deploy/executor/concerns/systemd.py +0 -88
  23. ominfra/manage/deploy/executor/concerns/user.py +0 -25
  24. ominfra/manage/deploy/executor/concerns/venv.py +0 -22
  25. ominfra/manage/deploy/executor/main.py +0 -119
  26. ominfra/manage/deploy/poly/__init__.py +0 -1
  27. ominfra/manage/deploy/poly/_main.py +0 -975
  28. ominfra/manage/deploy/poly/base.py +0 -178
  29. ominfra/manage/deploy/poly/configs.py +0 -38
  30. ominfra/manage/deploy/poly/deploy.py +0 -25
  31. ominfra/manage/deploy/poly/main.py +0 -18
  32. ominfra/manage/deploy/poly/nginx.py +0 -60
  33. ominfra/manage/deploy/poly/repo.py +0 -41
  34. ominfra/manage/deploy/poly/runtime.py +0 -39
  35. ominfra/manage/deploy/poly/site.py +0 -11
  36. ominfra/manage/deploy/poly/supervisor.py +0 -64
  37. ominfra/manage/deploy/poly/venv.py +0 -52
  38. ominfra/manage/deploy/remote.py +0 -91
  39. ominfra/manage/manage.py +0 -12
  40. ominfra/manage/new/__init__.py +0 -1
  41. ominfra/manage/new/commands/__init__.py +0 -0
  42. ominfra/manage/new/main.py +0 -234
  43. /ominfra/manage/{deploy → commands}/__init__.py +0 -0
  44. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/LICENSE +0 -0
  45. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/WHEEL +0 -0
  46. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/entry_points.txt +0 -0
  47. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/top_level.txt +0 -0
@@ -2,11 +2,11 @@
2
2
  # noinspection DuplicatedCode
3
3
  # @omlish-lite
4
4
  # @omlish-script
5
- # @omlish-amalg-output main.py
5
+ # @omlish-amalg-output ../manage/main.py
6
6
  # ruff: noqa: N802 UP006 UP007 UP036
7
7
  """
8
8
  manage.py -s 'docker run -i python:3.12'
9
- manage.py -qs 'ssh -i foo/bar foo@bar.baz' --python=python3.8
9
+ manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
10
10
  """
11
11
  import abc
12
12
  import base64
@@ -49,13 +49,14 @@ if sys.version_info < (3, 8):
49
49
 
50
50
 
51
51
  # commands/base.py
52
- CommandInputT = ta.TypeVar('CommandInputT', bound='Command.Input')
52
+ CommandT = ta.TypeVar('CommandT', bound='Command')
53
53
  CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
54
54
 
55
- # ../../../omlish/lite/cached.py
55
+ # ../../omlish/lite/cached.py
56
56
  T = ta.TypeVar('T')
57
+ CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
57
58
 
58
- # ../../../omlish/lite/check.py
59
+ # ../../omlish/lite/check.py
59
60
  SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
60
61
 
61
62
 
@@ -66,22 +67,24 @@ SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
66
67
  ##
67
68
 
68
69
 
69
- class Command(abc.ABC, ta.Generic[CommandInputT, CommandOutputT]):
70
- @dc.dataclass(frozen=True)
71
- class Input(abc.ABC): # noqa
72
- pass
73
-
70
+ @dc.dataclass(frozen=True)
71
+ class Command(abc.ABC, ta.Generic[CommandOutputT]):
74
72
  @dc.dataclass(frozen=True)
75
73
  class Output(abc.ABC): # noqa
76
74
  pass
77
75
 
76
+
77
+ ##
78
+
79
+
80
+ class CommandExecutor(abc.ABC, ta.Generic[CommandT, CommandOutputT]):
78
81
  @abc.abstractmethod
79
- def _execute(self, inp: CommandInputT) -> CommandOutputT:
82
+ def execute(self, i: CommandT) -> CommandOutputT:
80
83
  raise NotImplementedError
81
84
 
82
85
 
83
86
  ########################################
84
- # ../../../pyremote.py
87
+ # ../../pyremote.py
85
88
  """
86
89
  Basically this: https://mitogen.networkgenomics.com/howitworks.html
87
90
  """
@@ -203,6 +206,8 @@ _PYREMOTE_BOOTSTRAP_SRC_FD = 101
203
206
 
204
207
  _PYREMOTE_BOOTSTRAP_CHILD_PID_VAR = '_OPYR_CHILD_PID'
205
208
  _PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
209
+ _PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR = '_OPYR_CONTEXT_NAME'
210
+ _PYREMOTE_BOOTSTRAP_SRC_FILE_VAR = '_OPYR_SRC_FILE'
206
211
  _PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR = '_OPYR_OPTIONS_JSON'
207
212
 
208
213
  _PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
@@ -245,11 +250,10 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
245
250
  for f in [r0, w0, r1, w1]:
246
251
  os.close(f)
247
252
 
248
- # Save child pid to close after relaunch
253
+ # Save vars
249
254
  os.environ[_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR] = str(cp)
250
-
251
- # Save original argv0
252
255
  os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR] = sys.executable
256
+ os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR] = context_name
253
257
 
254
258
  # Start repl reading stdin from r0
255
259
  os.execl(sys.executable, sys.executable + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)))
@@ -300,6 +304,7 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
300
304
 
301
305
  '_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR',
302
306
  '_PYREMOTE_BOOTSTRAP_ARGV0_VAR',
307
+ '_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR',
303
308
 
304
309
  '_PYREMOTE_BOOTSTRAP_ACK0',
305
310
  '_PYREMOTE_BOOTSTRAP_ACK1',
@@ -335,14 +340,15 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
335
340
  class PyremotePayloadRuntime:
336
341
  input: ta.BinaryIO
337
342
  output: ta.BinaryIO
343
+ context_name: str
338
344
  main_src: str
339
345
  options: PyremoteBootstrapOptions
340
346
  env_info: PyremoteEnvInfo
341
347
 
342
348
 
343
349
  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:
350
+ # If src file var is not present we need to do initial finalization
351
+ if _PYREMOTE_BOOTSTRAP_SRC_FILE_VAR not in os.environ:
346
352
  # Read second copy of main src
347
353
  r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
348
354
  main_src = r1.read().decode('utf-8')
@@ -366,11 +372,14 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
366
372
  os.write(tfd, main_src.encode('utf-8'))
367
373
  os.close(tfd)
368
374
 
369
- # Set json options var
375
+ # Set vars
376
+ os.environ[_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR] = tfn
370
377
  os.environ[_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR] = options_json.decode('utf-8')
371
378
 
372
379
  # Re-exec temp file
373
- os.execl(os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR], sys.orig_argv[0], tfn)
380
+ exe = os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR]
381
+ context_name = os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR]
382
+ os.execl(exe, exe + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)), tfn)
374
383
 
375
384
  else:
376
385
  # Load options json var
@@ -378,12 +387,15 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
378
387
  options = PyremoteBootstrapOptions(**json.loads(options_json_str))
379
388
 
380
389
  # Read temp source file
381
- with open(sys.orig_argv[1]) as sf:
390
+ with open(os.environ.pop(_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR)) as sf:
382
391
  main_src = sf.read()
383
392
 
384
393
  # Restore original argv0
385
394
  sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
386
395
 
396
+ # Grab context name
397
+ context_name = os.environ.pop(_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR)
398
+
387
399
  # Write third ack
388
400
  os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
389
401
 
@@ -406,6 +418,7 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
406
418
  return PyremotePayloadRuntime(
407
419
  input=input,
408
420
  output=output,
421
+ context_name=context_name,
409
422
  main_src=main_src,
410
423
  options=options,
411
424
  env_info=env_info,
@@ -526,7 +539,7 @@ class PyremoteBootstrapDriver:
526
539
 
527
540
 
528
541
  ########################################
529
- # ../../../../omlish/lite/cached.py
542
+ # ../../../omlish/lite/cached.py
530
543
 
531
544
 
532
545
  class _cached_nullary: # noqa
@@ -550,8 +563,14 @@ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
550
563
  return _cached_nullary(fn)
551
564
 
552
565
 
566
+ def static_init(fn: CallableT) -> CallableT:
567
+ fn = cached_nullary(fn)
568
+ fn()
569
+ return fn
570
+
571
+
553
572
  ########################################
554
- # ../../../../omlish/lite/check.py
573
+ # ../../../omlish/lite/check.py
555
574
 
556
575
 
557
576
  def check_isinstance(v: ta.Any, spec: ta.Union[ta.Type[T], tuple]) -> T:
@@ -648,7 +667,7 @@ def check_non_empty(v: SizedT) -> SizedT:
648
667
 
649
668
 
650
669
  ########################################
651
- # ../../../../omlish/lite/json.py
670
+ # ../../../omlish/lite/json.py
652
671
 
653
672
 
654
673
  ##
@@ -679,7 +698,7 @@ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON
679
698
 
680
699
 
681
700
  ########################################
682
- # ../../../../omlish/lite/reflect.py
701
+ # ../../../omlish/lite/reflect.py
683
702
 
684
703
 
685
704
  _GENERIC_ALIAS_TYPES = (
@@ -734,7 +753,40 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
734
753
 
735
754
 
736
755
  ########################################
737
- # ../../../../omlish/lite/logs.py
756
+ # ../payload.py
757
+
758
+
759
+ @cached_nullary
760
+ def _get_self_src() -> str:
761
+ return inspect.getsource(sys.modules[__name__])
762
+
763
+
764
+ def _is_src_amalg(src: str) -> bool:
765
+ for l in src.splitlines(): # noqa
766
+ if l.startswith('# @omlish-amalg-output '):
767
+ return True
768
+ return False
769
+
770
+
771
+ @cached_nullary
772
+ def _is_self_amalg() -> bool:
773
+ return _is_src_amalg(_get_self_src())
774
+
775
+
776
+ def get_payload_src(*, file: ta.Optional[str]) -> str:
777
+ if file is not None:
778
+ with open(file) as f:
779
+ return f.read()
780
+
781
+ if _is_self_amalg():
782
+ return _get_self_src()
783
+
784
+ import importlib.resources
785
+ return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
786
+
787
+
788
+ ########################################
789
+ # ../../../omlish/lite/logs.py
738
790
  """
739
791
  TODO:
740
792
  - translate json keys
@@ -1004,7 +1056,7 @@ def configure_standard_logging(
1004
1056
 
1005
1057
 
1006
1058
  ########################################
1007
- # ../../../../omlish/lite/marshal.py
1059
+ # ../../../omlish/lite/marshal.py
1008
1060
  """
1009
1061
  TODO:
1010
1062
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
@@ -1351,7 +1403,7 @@ def unmarshal_obj(o: ta.Any, ty: ta.Union[ta.Type[T], ta.Any]) -> T:
1351
1403
 
1352
1404
 
1353
1405
  ########################################
1354
- # ../../../../omlish/lite/runtime.py
1406
+ # ../../../omlish/lite/runtime.py
1355
1407
 
1356
1408
 
1357
1409
  @cached_nullary
@@ -1368,7 +1420,7 @@ def check_runtime_version() -> None:
1368
1420
 
1369
1421
 
1370
1422
  ########################################
1371
- # ../../../../omlish/lite/subprocesses.py
1423
+ # ../../../omlish/lite/subprocesses.py
1372
1424
 
1373
1425
 
1374
1426
  ##
@@ -1498,24 +1550,23 @@ def subprocess_close(
1498
1550
  ##
1499
1551
 
1500
1552
 
1501
- class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Output']):
1502
- @dc.dataclass(frozen=True)
1503
- class Input(Command.Input):
1504
- args: ta.Sequence[str]
1553
+ @dc.dataclass(frozen=True)
1554
+ class SubprocessCommand(Command['SubprocessCommand.Output']):
1555
+ args: ta.Sequence[str]
1505
1556
 
1506
- shell: bool = False
1507
- cwd: ta.Optional[str] = None
1508
- env: ta.Optional[ta.Mapping[str, str]] = None
1557
+ shell: bool = False
1558
+ cwd: ta.Optional[str] = None
1559
+ env: ta.Optional[ta.Mapping[str, str]] = None
1509
1560
 
1510
- capture_stdout: bool = False
1511
- capture_stderr: bool = False
1561
+ capture_stdout: bool = False
1562
+ capture_stderr: bool = False
1512
1563
 
1513
- input: ta.Optional[bytes] = None
1514
- timeout: ta.Optional[float] = None
1564
+ input: ta.Optional[bytes] = None
1565
+ timeout: ta.Optional[float] = None
1515
1566
 
1516
- def __post_init__(self) -> None:
1517
- if isinstance(self.args, str):
1518
- raise TypeError(self.args)
1567
+ def __post_init__(self) -> None:
1568
+ if isinstance(self.args, str):
1569
+ raise TypeError(self.args)
1519
1570
 
1520
1571
  @dc.dataclass(frozen=True)
1521
1572
  class Output(Command.Output):
@@ -1527,7 +1578,12 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
1527
1578
  stdout: ta.Optional[bytes] = None
1528
1579
  stderr: ta.Optional[bytes] = None
1529
1580
 
1530
- def _execute(self, inp: Input) -> Output:
1581
+
1582
+ ##
1583
+
1584
+
1585
+ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
1586
+ def execute(self, inp: SubprocessCommand) -> SubprocessCommand.Output:
1531
1587
  proc = subprocess.Popen(
1532
1588
  subprocess_maybe_shell_wrap_exec(*inp.args),
1533
1589
 
@@ -1558,6 +1614,101 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
1558
1614
  )
1559
1615
 
1560
1616
 
1617
+ ########################################
1618
+ # ../spawning.py
1619
+
1620
+
1621
+ class PySpawner:
1622
+ DEFAULT_PYTHON = 'python3'
1623
+
1624
+ def __init__(
1625
+ self,
1626
+ src: str,
1627
+ *,
1628
+ shell: ta.Optional[str] = None,
1629
+ shell_quote: bool = False,
1630
+ python: str = DEFAULT_PYTHON,
1631
+ stderr: ta.Optional[ta.Literal['pipe', 'stdout', 'devnull']] = None,
1632
+ ) -> None:
1633
+ super().__init__()
1634
+
1635
+ self._src = src
1636
+ self._shell = shell
1637
+ self._shell_quote = shell_quote
1638
+ self._python = python
1639
+ self._stderr = stderr
1640
+
1641
+ #
1642
+
1643
+ class _PreparedCmd(ta.NamedTuple):
1644
+ cmd: ta.Sequence[str]
1645
+ shell: bool
1646
+
1647
+ def _prepare_cmd(self) -> _PreparedCmd:
1648
+ if self._shell is not None:
1649
+ sh_src = f'{self._python} -c {shlex.quote(self._src)}'
1650
+ if self._shell_quote:
1651
+ sh_src = shlex.quote(sh_src)
1652
+ sh_cmd = f'{self._shell} {sh_src}'
1653
+ return PySpawner._PreparedCmd(
1654
+ cmd=[sh_cmd],
1655
+ shell=True,
1656
+ )
1657
+
1658
+ else:
1659
+ return PySpawner._PreparedCmd(
1660
+ cmd=[self._python, '-c', self._src],
1661
+ shell=False,
1662
+ )
1663
+
1664
+ #
1665
+
1666
+ _STDERR_KWARG_MAP: ta.Mapping[str, int] = {
1667
+ 'pipe': subprocess.PIPE,
1668
+ 'stdout': subprocess.STDOUT,
1669
+ 'devnull': subprocess.DEVNULL,
1670
+ }
1671
+
1672
+ @dc.dataclass(frozen=True)
1673
+ class Spawned:
1674
+ stdin: ta.IO
1675
+ stdout: ta.IO
1676
+ stderr: ta.Optional[ta.IO]
1677
+
1678
+ @contextlib.contextmanager
1679
+ def spawn(
1680
+ self,
1681
+ *,
1682
+ timeout: ta.Optional[float] = None,
1683
+ ) -> ta.Generator[Spawned, None, None]:
1684
+ pc = self._prepare_cmd()
1685
+
1686
+ with subprocess.Popen(
1687
+ subprocess_maybe_shell_wrap_exec(*pc.cmd),
1688
+ shell=pc.shell,
1689
+ stdin=subprocess.PIPE,
1690
+ stdout=subprocess.PIPE,
1691
+ stderr=self._STDERR_KWARG_MAP[self._stderr] if self._stderr is not None else None,
1692
+ ) as proc:
1693
+ stdin = check_not_none(proc.stdin)
1694
+ stdout = check_not_none(proc.stdout)
1695
+
1696
+ try:
1697
+ yield PySpawner.Spawned(
1698
+ stdin=stdin,
1699
+ stdout=stdout,
1700
+ stderr=proc.stderr,
1701
+ )
1702
+
1703
+ finally:
1704
+ try:
1705
+ stdin.close()
1706
+ except BrokenPipeError:
1707
+ pass
1708
+
1709
+ proc.wait(timeout)
1710
+
1711
+
1561
1712
  ########################################
1562
1713
  # main.py
1563
1714
 
@@ -1570,29 +1721,23 @@ _COMMAND_TYPES = {
1570
1721
  }
1571
1722
 
1572
1723
 
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),
1724
+ @static_init
1725
+ def _register_command_marshaling() -> None:
1726
+ for fn in [
1727
+ lambda c: c,
1728
+ lambda c: c.Output,
1729
+ ]:
1730
+ register_opj_marshaler(
1731
+ fn(Command),
1732
+ PolymorphicObjMarshaler.of([
1733
+ PolymorphicObjMarshaler.Impl(
1734
+ fn(cty),
1735
+ k,
1736
+ get_obj_marshaler(fn(cty)),
1737
+ )
1738
+ for k, cty in _COMMAND_TYPES.items()
1739
+ ]),
1592
1740
  )
1593
- for k, cty in _COMMAND_TYPES.items()
1594
- ]),
1595
- )
1596
1741
 
1597
1742
 
1598
1743
  ##
@@ -1630,12 +1775,12 @@ def _remote_main() -> None:
1630
1775
  rt = pyremote_bootstrap_finalize() # noqa
1631
1776
 
1632
1777
  while True:
1633
- i = _recv_obj(rt.input, Command.Input)
1778
+ i = _recv_obj(rt.input, Command)
1634
1779
  if i is None:
1635
1780
  break
1636
1781
 
1637
- if isinstance(i, SubprocessCommand.Input):
1638
- o = SubprocessCommand()._execute(i) # noqa
1782
+ if isinstance(i, SubprocessCommand):
1783
+ o = SubprocessCommandExecutor().execute(i) # noqa
1639
1784
  else:
1640
1785
  raise TypeError(i)
1641
1786
 
@@ -1645,38 +1790,6 @@ def _remote_main() -> None:
1645
1790
  ##
1646
1791
 
1647
1792
 
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
- ##
1678
-
1679
-
1680
1793
  def _main() -> None:
1681
1794
  import argparse
1682
1795
 
@@ -1685,19 +1798,20 @@ def _main() -> None:
1685
1798
  parser.add_argument('-s', '--shell')
1686
1799
  parser.add_argument('-q', '--shell-quote', action='store_true')
1687
1800
  parser.add_argument('--python', default='python3')
1688
- parser.add_argument('--_amalg-file')
1801
+ parser.add_argument('--debug', action='store_true')
1802
+ parser.add_argument('--_payload-file')
1689
1803
 
1690
1804
  args = parser.parse_args()
1691
1805
 
1692
1806
  #
1693
1807
 
1694
- amalg_src = _get_amalg_src(amalg_file=args._amalg_file) # noqa
1808
+ payload_src = get_payload_src(file=args._payload_file) # noqa
1695
1809
 
1696
1810
  #
1697
1811
 
1698
1812
  remote_src = '\n\n'.join([
1699
1813
  '__name__ = "__remote__"',
1700
- amalg_src,
1814
+ payload_src,
1701
1815
  '_remote_main()',
1702
1816
  ])
1703
1817
 
@@ -1705,60 +1819,41 @@ def _main() -> None:
1705
1819
 
1706
1820
  bs_src = pyremote_build_bootstrap_cmd(__package__ or 'manage')
1707
1821
 
1708
- if args.shell is not None:
1709
- sh_src = f'{args.python} -c {shlex.quote(bs_src)}'
1710
- if args.shell_quote:
1711
- sh_src = shlex.quote(sh_src)
1712
- sh_cmd = f'{args.shell} {sh_src}'
1713
- cmd = [sh_cmd]
1714
- shell = True
1715
- else:
1716
- cmd = [args.python, '-c', bs_src]
1717
- shell = False
1718
-
1719
- proc = subprocess.Popen(
1720
- subprocess_maybe_shell_wrap_exec(*cmd),
1721
- shell=shell,
1722
- stdin=subprocess.PIPE,
1723
- stdout=subprocess.PIPE,
1724
- )
1725
-
1726
- stdin = check_not_none(proc.stdin)
1727
- stdout = check_not_none(proc.stdout)
1728
-
1729
- res = PyremoteBootstrapDriver( # noqa
1730
- remote_src,
1731
- PyremoteBootstrapOptions(
1732
- # debug=True,
1733
- ),
1734
- ).run(stdin, stdout)
1735
- # print(res)
1736
-
1737
1822
  #
1738
1823
 
1739
- for ci in [
1740
- SubprocessCommand.Input(
1741
- args=['python3', '-'],
1742
- input=b'print(1)\n',
1743
- capture_stdout=True,
1744
- ),
1745
- SubprocessCommand.Input(
1746
- args=['uname'],
1747
- capture_stdout=True,
1748
- ),
1749
- ]:
1750
- _send_obj(stdin, ci, Command.Input)
1751
-
1752
- o = _recv_obj(stdout, Command.Output)
1753
-
1754
- print(o)
1824
+ spawner = PySpawner(
1825
+ bs_src,
1826
+ shell=args.shell,
1827
+ shell_quote=args.shell_quote,
1828
+ python=args.python,
1829
+ )
1830
+ with spawner.spawn() as proc:
1831
+ res = PyremoteBootstrapDriver( # noqa
1832
+ remote_src,
1833
+ PyremoteBootstrapOptions(
1834
+ debug=args.debug,
1835
+ ),
1836
+ ).run(proc.stdin, proc.stdout)
1837
+ # print(res)
1755
1838
 
1756
- try:
1757
- stdin.close()
1758
- except BrokenPipeError:
1759
- pass
1839
+ #
1760
1840
 
1761
- proc.wait()
1841
+ for ci in [
1842
+ SubprocessCommand(
1843
+ args=['python3', '-'],
1844
+ input=b'print(1)\n',
1845
+ capture_stdout=True,
1846
+ ),
1847
+ SubprocessCommand(
1848
+ args=['uname'],
1849
+ capture_stdout=True,
1850
+ ),
1851
+ ]:
1852
+ _send_obj(proc.stdin, ci, Command)
1853
+
1854
+ o = _recv_obj(proc.stdout, Command.Output)
1855
+
1856
+ print(o)
1762
1857
 
1763
1858
 
1764
1859
  if __name__ == '__main__':
@@ -101,6 +101,7 @@ V = ta.TypeVar('V')
101
101
 
102
102
  # ../../omlish/lite/cached.py
103
103
  T = ta.TypeVar('T')
104
+ CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
104
105
 
105
106
  # ../../omlish/lite/check.py
106
107
  SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
@@ -1454,6 +1455,12 @@ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1454
1455
  return _cached_nullary(fn)
1455
1456
 
1456
1457
 
1458
+ def static_init(fn: CallableT) -> CallableT:
1459
+ fn = cached_nullary(fn)
1460
+ fn()
1461
+ return fn
1462
+
1463
+
1457
1464
  ########################################
1458
1465
  # ../../../omlish/lite/check.py
1459
1466
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev138
3
+ Version: 0.0.0.dev140
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omdev==0.0.0.dev138
16
- Requires-Dist: omlish==0.0.0.dev138
15
+ Requires-Dist: omdev==0.0.0.dev140
16
+ Requires-Dist: omlish==0.0.0.dev140
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"