ominfra 0.0.0.dev155__tar.gz → 0.0.0.dev157__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. {ominfra-0.0.0.dev155/ominfra.egg-info → ominfra-0.0.0.dev157}/PKG-INFO +3 -3
  2. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/subprocess.py +3 -4
  3. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/git.py +3 -3
  4. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/venvs.py +4 -4
  5. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/main.py +33 -4
  6. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/spawning.py +3 -8
  7. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/packages.py +13 -15
  8. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/scripts/journald2aws.py +184 -129
  9. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/scripts/manage.py +1276 -325
  10. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/scripts/supervisor.py +44 -31
  11. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/configs.py +2 -0
  12. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/supervisor.py +2 -33
  13. ominfra-0.0.0.dev157/ominfra/supervisor/utils/os.py +86 -0
  14. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157/ominfra.egg-info}/PKG-INFO +3 -3
  15. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra.egg-info/requires.txt +2 -2
  16. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/pyproject.toml +3 -3
  17. ominfra-0.0.0.dev155/ominfra/supervisor/utils/os.py +0 -45
  18. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/LICENSE +0 -0
  19. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/MANIFEST.in +0 -0
  20. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/README.rst +0 -0
  21. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/.manifests.json +0 -0
  22. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/__about__.py +0 -0
  23. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/__init__.py +0 -0
  24. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/__init__.py +0 -0
  25. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/__init__.py +0 -0
  26. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/__main__.py +0 -0
  27. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/auth.py +0 -0
  28. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/cli.py +0 -0
  29. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/dataclasses.py +0 -0
  30. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/__init__.py +0 -0
  31. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/__main__.py +0 -0
  32. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/cursor.py +0 -0
  33. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/driver.py +0 -0
  34. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/main.py +0 -0
  35. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/journald2aws/poster.py +0 -0
  36. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/logs.py +0 -0
  37. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/aws/metadata.py +0 -0
  38. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/gcp/__init__.py +0 -0
  39. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/clouds/gcp/auth.py +0 -0
  40. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/cmds.py +0 -0
  41. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/configs.py +0 -0
  42. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/journald/__init__.py +0 -0
  43. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/journald/fields.py +0 -0
  44. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/journald/genmessages.py +0 -0
  45. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/journald/messages.py +0 -0
  46. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/journald/tailer.py +0 -0
  47. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/__init__.py +0 -0
  48. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/__main__.py +0 -0
  49. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/bootstrap.py +0 -0
  50. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/bootstrap_.py +0 -0
  51. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/__init__.py +0 -0
  52. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/base.py +0 -0
  53. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/inject.py +0 -0
  54. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/local.py +0 -0
  55. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/marshal.py +0 -0
  56. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/ping.py +0 -0
  57. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/commands/types.py +0 -0
  58. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/config.py +0 -0
  59. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/__init__.py +0 -0
  60. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/apps.py +0 -0
  61. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/commands.py +0 -0
  62. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/config.py +0 -0
  63. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/inject.py +0 -0
  64. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/interp.py +0 -0
  65. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/paths.py +0 -0
  66. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/deploy/types.py +0 -0
  67. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/inject.py +0 -0
  68. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/marshal.py +0 -0
  69. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/__init__.py +0 -0
  70. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/_main.py +0 -0
  71. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/channel.py +0 -0
  72. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/config.py +0 -0
  73. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/connection.py +0 -0
  74. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/execution.py +0 -0
  75. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/inject.py +0 -0
  76. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/remote/payload.py +0 -0
  77. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/__init__.py +0 -0
  78. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/commands.py +0 -0
  79. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/config.py +0 -0
  80. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/inject.py +0 -0
  81. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/system/platforms.py +0 -0
  82. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/targets/__init__.py +0 -0
  83. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/targets/connection.py +0 -0
  84. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/targets/inject.py +0 -0
  85. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/manage/targets/targets.py +0 -0
  86. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/pyremote.py +0 -0
  87. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/scripts/__init__.py +0 -0
  88. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/ssh.py +0 -0
  89. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/LICENSE.txt +0 -0
  90. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/__init__.py +0 -0
  91. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/__main__.py +0 -0
  92. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/dispatchers.py +0 -0
  93. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/dispatchersimpl.py +0 -0
  94. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/events.py +0 -0
  95. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/exceptions.py +0 -0
  96. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/groups.py +0 -0
  97. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/groupsimpl.py +0 -0
  98. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/http.py +0 -0
  99. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/inject.py +0 -0
  100. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/io.py +0 -0
  101. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/main.py +0 -0
  102. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/pipes.py +0 -0
  103. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/privileges.py +0 -0
  104. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/process.py +0 -0
  105. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/processimpl.py +0 -0
  106. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/setup.py +0 -0
  107. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/setupimpl.py +0 -0
  108. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/signals.py +0 -0
  109. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/spawning.py +0 -0
  110. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/spawningimpl.py +0 -0
  111. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/states.py +0 -0
  112. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/types.py +0 -0
  113. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/__init__.py +0 -0
  114. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/collections.py +0 -0
  115. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/diag.py +0 -0
  116. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/fds.py +0 -0
  117. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/fs.py +0 -0
  118. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/ostypes.py +0 -0
  119. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/signals.py +0 -0
  120. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/strings.py +0 -0
  121. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/supervisor/utils/users.py +0 -0
  122. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/tailscale/__init__.py +0 -0
  123. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/tailscale/api.py +0 -0
  124. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/tailscale/cli.py +0 -0
  125. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/threadworkers.py +0 -0
  126. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/tools/__init__.py +0 -0
  127. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra/tools/listresources.py +0 -0
  128. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra.egg-info/SOURCES.txt +0 -0
  129. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra.egg-info/dependency_links.txt +0 -0
  130. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra.egg-info/entry_points.txt +0 -0
  131. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/ominfra.egg-info/top_level.txt +0 -0
  132. {ominfra-0.0.0.dev155 → ominfra-0.0.0.dev157}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev155
3
+ Version: 0.0.0.dev157
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.dev155
16
- Requires-Dist: omlish==0.0.0.dev155
15
+ Requires-Dist: omdev==0.0.0.dev157
16
+ Requires-Dist: omlish==0.0.0.dev157
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -6,8 +6,7 @@ import subprocess
6
6
  import time
7
7
  import typing as ta
8
8
 
9
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_communicate
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
9
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
10
  from omlish.lite.check import check
12
11
  from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
12
  from omlish.lite.subprocesses import SubprocessChannelOption
@@ -51,7 +50,7 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
51
50
  class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
52
51
  async def execute(self, cmd: SubprocessCommand) -> SubprocessCommand.Output:
53
52
  proc: asyncio.subprocess.Process
54
- async with asyncio_subprocess_popen(
53
+ async with asyncio_subprocesses.popen(
55
54
  *subprocess_maybe_shell_wrap_exec(*cmd.cmd),
56
55
 
57
56
  shell=cmd.shell,
@@ -65,7 +64,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
65
64
  timeout=cmd.timeout,
66
65
  ) as proc:
67
66
  start_time = time.time()
68
- stdout, stderr = await asyncio_subprocess_communicate(
67
+ stdout, stderr = await asyncio_subprocesses.communicate(
69
68
  proc,
70
69
  input=cmd.input,
71
70
  timeout=cmd.timeout,
@@ -13,7 +13,7 @@ import functools
13
13
  import os.path
14
14
  import typing as ta
15
15
 
16
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
16
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
17
17
  from omlish.lite.cached import async_cached_nullary
18
18
  from omlish.lite.check import check
19
19
 
@@ -92,7 +92,7 @@ class DeployGitManager(DeployPathOwner):
92
92
  return f'https://{self._repo.host}/{self._repo.path}'
93
93
 
94
94
  async def _call(self, *cmd: str) -> None:
95
- await asyncio_subprocess_check_call(
95
+ await asyncio_subprocesses.check_call(
96
96
  *cmd,
97
97
  cwd=self._dir,
98
98
  )
@@ -118,7 +118,7 @@ class DeployGitManager(DeployPathOwner):
118
118
  # FIXME: temp dir swap
119
119
  os.makedirs(dst_dir)
120
120
 
121
- dst_call = functools.partial(asyncio_subprocess_check_call, cwd=dst_dir)
121
+ dst_call = functools.partial(asyncio_subprocesses.check_call, cwd=dst_dir)
122
122
  await dst_call('git', 'init')
123
123
 
124
124
  await dst_call('git', 'remote', 'add', 'local', self._dir)
@@ -7,7 +7,7 @@ TODO:
7
7
  import os.path
8
8
  import typing as ta
9
9
 
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
10
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
11
 
12
12
  from .paths import DeployPath
13
13
  from .paths import DeployPathOwner
@@ -40,7 +40,7 @@ class DeployVenvManager(DeployPathOwner):
40
40
  ) -> None:
41
41
  sys_exe = 'python3'
42
42
 
43
- await asyncio_subprocess_check_call(sys_exe, '-m', 'venv', venv_dir)
43
+ await asyncio_subprocesses.check_call(sys_exe, '-m', 'venv', venv_dir)
44
44
 
45
45
  #
46
46
 
@@ -52,12 +52,12 @@ class DeployVenvManager(DeployPathOwner):
52
52
 
53
53
  if os.path.isfile(reqs_txt):
54
54
  if use_uv:
55
- await asyncio_subprocess_check_call(venv_exe, '-m', 'pip', 'install', 'uv')
55
+ await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
56
56
  pip_cmd = ['-m', 'uv', 'pip']
57
57
  else:
58
58
  pip_cmd = ['-m', 'pip']
59
59
 
60
- await asyncio_subprocess_check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
60
+ await asyncio_subprocesses.check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
61
61
 
62
62
  async def setup_app_venv(self, app_tag: DeployAppTag) -> None:
63
63
  await self.setup_venv(
@@ -6,18 +6,23 @@ manage.py -s 'docker run -i python:3.12'
6
6
  manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
7
7
  """
8
8
  import asyncio
9
+ import dataclasses as dc
9
10
  import json
11
+ import os.path
10
12
  import sys
11
13
  import typing as ta
12
14
 
13
15
  from omlish.argparse.cli import ArgparseCli
14
16
  from omlish.argparse.cli import argparse_arg
15
17
  from omlish.argparse.cli import argparse_command
18
+ from omlish.lite.cached import cached_nullary
19
+ from omlish.lite.check import check
16
20
  from omlish.lite.logs import log # noqa
17
21
  from omlish.lite.marshal import ObjMarshalerManager
18
22
  from omlish.lite.marshal import ObjMarshalOptions
19
23
  from omlish.lite.pycharm import PycharmRemoteDebug
20
24
 
25
+ from ..configs import read_config_file
21
26
  from .bootstrap import MainBootstrap
22
27
  from .bootstrap_ import main_bootstrap
23
28
  from .commands.base import Command
@@ -28,7 +33,28 @@ from .targets.connection import ManageTargetConnector
28
33
  from .targets.targets import ManageTarget
29
34
 
30
35
 
36
+ @dc.dataclass(frozen=True)
37
+ class ManageConfig:
38
+ targets: ta.Optional[ta.Mapping[str, ManageTarget]] = None
39
+
40
+
31
41
  class MainCli(ArgparseCli):
42
+ config_file: ta.Optional[str] = argparse_arg('--config-file', help='Config file path') # type: ignore
43
+
44
+ @cached_nullary
45
+ def config(self) -> ManageConfig:
46
+ if (cf := self.config_file) is None:
47
+ cf = os.path.expanduser('~/.omlish/manage.yml')
48
+ if not os.path.isfile(cf):
49
+ cf = None
50
+
51
+ if cf is None:
52
+ return ManageConfig()
53
+ else:
54
+ return read_config_file(cf, ManageConfig)
55
+
56
+ #
57
+
32
58
  @argparse_command(
33
59
  argparse_arg('--_payload-file'),
34
60
 
@@ -80,10 +106,13 @@ class MainCli(ArgparseCli):
80
106
 
81
107
  msh = injector[ObjMarshalerManager]
82
108
 
83
- ts = self.args.target
84
- if not ts.startswith('{'):
85
- ts = json.dumps({ts: {}})
86
- tgt: ManageTarget = msh.unmarshal_obj(json.loads(ts), ManageTarget)
109
+ tgt: ManageTarget
110
+ if not (ts := self.args.target).startswith('{'):
111
+ tgt = check.not_none(self.config().targets)[ts]
112
+ else:
113
+ tgt = msh.unmarshal_obj(json.loads(ts), ManageTarget)
114
+
115
+ #
87
116
 
88
117
  cmds: ta.List[Command] = []
89
118
  cmd: Command
@@ -7,11 +7,10 @@ import shlex
7
7
  import subprocess
8
8
  import typing as ta
9
9
 
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
10
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
11
  from omlish.lite.check import check
12
12
  from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
13
  from omlish.lite.subprocesses import SubprocessChannelOption
14
- from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
15
14
 
16
15
 
17
16
  ##
@@ -82,12 +81,8 @@ class SubprocessRemoteSpawning(RemoteSpawning):
82
81
  ) -> ta.AsyncGenerator[RemoteSpawning.Spawned, None]:
83
82
  pc = self._prepare_cmd(tgt, src)
84
83
 
85
- cmd = pc.cmd
86
- if not debug:
87
- cmd = subprocess_maybe_shell_wrap_exec(*cmd)
88
-
89
- async with asyncio_subprocess_popen(
90
- *cmd,
84
+ async with asyncio_subprocesses.popen(
85
+ *pc.cmd,
91
86
  shell=pc.shell,
92
87
  stdin=subprocess.PIPE,
93
88
  stdout=subprocess.PIPE,
@@ -9,9 +9,7 @@ import json
9
9
  import os
10
10
  import typing as ta
11
11
 
12
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
13
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_output
14
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_run
12
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
15
13
  from omlish.lite.check import check
16
14
 
17
15
 
@@ -44,10 +42,10 @@ class SystemPackageManager(abc.ABC):
44
42
 
45
43
  class BrewSystemPackageManager(SystemPackageManager):
46
44
  async def update(self) -> None:
47
- await asyncio_subprocess_check_call('brew', 'update')
45
+ await asyncio_subprocesses.check_call('brew', 'update')
48
46
 
49
47
  async def upgrade(self) -> None:
50
- await asyncio_subprocess_check_call('brew', 'upgrade')
48
+ await asyncio_subprocesses.check_call('brew', 'upgrade')
51
49
 
52
50
  async def install(self, *packages: SystemPackageOrStr) -> None:
53
51
  es: ta.List[str] = []
@@ -56,11 +54,11 @@ class BrewSystemPackageManager(SystemPackageManager):
56
54
  es.append(p.name + (f'@{p.version}' if p.version is not None else ''))
57
55
  else:
58
56
  es.append(p)
59
- await asyncio_subprocess_check_call('brew', 'install', *es)
57
+ await asyncio_subprocesses.check_call('brew', 'install', *es)
60
58
 
61
59
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
62
60
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
63
- o = await asyncio_subprocess_check_output('brew', 'info', '--json', *pns)
61
+ o = await asyncio_subprocesses.check_output('brew', 'info', '--json', *pns)
64
62
  j = json.loads(o.decode())
65
63
  d: ta.Dict[str, SystemPackage] = {}
66
64
  for e in j:
@@ -79,18 +77,18 @@ class AptSystemPackageManager(SystemPackageManager):
79
77
  }
80
78
 
81
79
  async def update(self) -> None:
82
- await asyncio_subprocess_check_call('sudo', 'apt', 'update', env={**os.environ, **self._APT_ENV})
80
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'update', env={**os.environ, **self._APT_ENV})
83
81
 
84
82
  async def upgrade(self) -> None:
85
- await asyncio_subprocess_check_call('sudo', 'apt', 'upgrade', '-y', env={**os.environ, **self._APT_ENV})
83
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'upgrade', '-y', env={**os.environ, **self._APT_ENV})
86
84
 
87
85
  async def install(self, *packages: SystemPackageOrStr) -> None:
88
86
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
89
- await asyncio_subprocess_check_call('sudo', 'apt', 'install', '-y', *pns, env={**os.environ, **self._APT_ENV})
87
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'install', '-y', *pns, env={**os.environ, **self._APT_ENV})
90
88
 
91
89
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
92
90
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
93
- out = await asyncio_subprocess_run(
91
+ out = await asyncio_subprocesses.run(
94
92
  'dpkg-query', '-W', '-f=${Package}=${Version}\n', *pns,
95
93
  capture_output=True,
96
94
  check=False,
@@ -107,20 +105,20 @@ class AptSystemPackageManager(SystemPackageManager):
107
105
 
108
106
  class YumSystemPackageManager(SystemPackageManager):
109
107
  async def update(self) -> None:
110
- await asyncio_subprocess_check_call('sudo', 'yum', 'check-update')
108
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'check-update')
111
109
 
112
110
  async def upgrade(self) -> None:
113
- await asyncio_subprocess_check_call('sudo', 'yum', 'update')
111
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'update')
114
112
 
115
113
  async def install(self, *packages: SystemPackageOrStr) -> None:
116
114
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
117
- await asyncio_subprocess_check_call('sudo', 'yum', 'install', *pns)
115
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'install', *pns)
118
116
 
119
117
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
120
118
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
121
119
  d: ta.Dict[str, SystemPackage] = {}
122
120
  for pn in pns:
123
- out = await asyncio_subprocess_run(
121
+ out = await asyncio_subprocesses.run(
124
122
  'rpm', '-q', pn,
125
123
  capture_output=True,
126
124
  )
@@ -932,8 +932,8 @@ class _CachedNullary(_AbstractCachedNullary):
932
932
  return self._value
933
933
 
934
934
 
935
- def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
936
- return _CachedNullary(fn)
935
+ def cached_nullary(fn: CallableT) -> CallableT:
936
+ return _CachedNullary(fn) # type: ignore
937
937
 
938
938
 
939
939
  def static_init(fn: CallableT) -> CallableT:
@@ -2559,6 +2559,7 @@ TODO:
2559
2559
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
2560
2560
  - namedtuple
2561
2561
  - literals
2562
+ - newtypes?
2562
2563
  """
2563
2564
 
2564
2565
 
@@ -3593,168 +3594,222 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
3593
3594
  _SUBPROCESS_SHELL_WRAP_EXECS = False
3594
3595
 
3595
3596
 
3596
- def subprocess_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
3597
- return ('sh', '-c', ' '.join(map(shlex.quote, args)))
3597
+ def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
3598
+ return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
3598
3599
 
3599
3600
 
3600
- def subprocess_maybe_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
3601
+ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
3601
3602
  if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
3602
- return subprocess_shell_wrap_exec(*args)
3603
+ return subprocess_shell_wrap_exec(*cmd)
3603
3604
  else:
3604
- return args
3605
-
3606
-
3607
- def prepare_subprocess_invocation(
3608
- *args: str,
3609
- env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3610
- extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3611
- quiet: bool = False,
3612
- shell: bool = False,
3613
- **kwargs: ta.Any,
3614
- ) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
3615
- log.debug('prepare_subprocess_invocation: args=%r', args)
3616
- if extra_env:
3617
- log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
3618
-
3619
- if extra_env:
3620
- env = {**(env if env is not None else os.environ), **extra_env}
3621
-
3622
- if quiet and 'stderr' not in kwargs:
3623
- if not log.isEnabledFor(logging.DEBUG):
3624
- kwargs['stderr'] = subprocess.DEVNULL
3625
-
3626
- if not shell:
3627
- args = subprocess_maybe_shell_wrap_exec(*args)
3628
-
3629
- return args, dict(
3630
- env=env,
3631
- shell=shell,
3632
- **kwargs,
3633
- )
3605
+ return cmd
3634
3606
 
3635
3607
 
3636
3608
  ##
3637
3609
 
3638
3610
 
3639
- @contextlib.contextmanager
3640
- def subprocess_common_context(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
3641
- start_time = time.time()
3642
- try:
3643
- log.debug('subprocess_common_context.try: args=%r', args)
3644
- yield
3645
-
3646
- except Exception as exc: # noqa
3647
- log.debug('subprocess_common_context.except: exc=%r', exc)
3648
- raise
3611
+ def subprocess_close(
3612
+ proc: subprocess.Popen,
3613
+ timeout: ta.Optional[float] = None,
3614
+ ) -> None:
3615
+ # TODO: terminate, sleep, kill
3616
+ if proc.stdout:
3617
+ proc.stdout.close()
3618
+ if proc.stderr:
3619
+ proc.stderr.close()
3620
+ if proc.stdin:
3621
+ proc.stdin.close()
3649
3622
 
3650
- finally:
3651
- end_time = time.time()
3652
- elapsed_s = end_time - start_time
3653
- log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
3623
+ proc.wait(timeout)
3654
3624
 
3655
3625
 
3656
3626
  ##
3657
3627
 
3658
3628
 
3659
- def subprocess_check_call(
3660
- *args: str,
3661
- stdout: ta.Any = sys.stderr,
3662
- **kwargs: ta.Any,
3663
- ) -> None:
3664
- args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
3665
- with subprocess_common_context(*args, **kwargs):
3666
- return subprocess.check_call(args, **kwargs) # type: ignore
3629
+ class AbstractSubprocesses(abc.ABC): # noqa
3630
+ DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
3631
+
3632
+ def __init__(
3633
+ self,
3634
+ *,
3635
+ log: ta.Optional[logging.Logger] = None,
3636
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3637
+ ) -> None:
3638
+ super().__init__()
3667
3639
 
3640
+ self._log = log if log is not None else self.DEFAULT_LOGGER
3641
+ self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
3668
3642
 
3669
- def subprocess_check_output(
3670
- *args: str,
3671
- **kwargs: ta.Any,
3672
- ) -> bytes:
3673
- args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
3674
- with subprocess_common_context(*args, **kwargs):
3675
- return subprocess.check_output(args, **kwargs)
3643
+ #
3676
3644
 
3645
+ def prepare_args(
3646
+ self,
3647
+ *cmd: str,
3648
+ env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3649
+ extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3650
+ quiet: bool = False,
3651
+ shell: bool = False,
3652
+ **kwargs: ta.Any,
3653
+ ) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
3654
+ if self._log:
3655
+ self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
3656
+ if extra_env:
3657
+ self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
3677
3658
 
3678
- def subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
3679
- return subprocess_check_output(*args, **kwargs).decode().strip()
3659
+ if extra_env:
3660
+ env = {**(env if env is not None else os.environ), **extra_env}
3680
3661
 
3662
+ if quiet and 'stderr' not in kwargs:
3663
+ if self._log and not self._log.isEnabledFor(logging.DEBUG):
3664
+ kwargs['stderr'] = subprocess.DEVNULL
3681
3665
 
3682
- ##
3666
+ if not shell:
3667
+ cmd = subprocess_maybe_shell_wrap_exec(*cmd)
3683
3668
 
3669
+ return cmd, dict(
3670
+ env=env,
3671
+ shell=shell,
3672
+ **kwargs,
3673
+ )
3684
3674
 
3685
- DEFAULT_SUBPROCESS_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
3686
- FileNotFoundError,
3687
- subprocess.CalledProcessError,
3688
- )
3675
+ @contextlib.contextmanager
3676
+ def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
3677
+ start_time = time.time()
3678
+ try:
3679
+ if self._log:
3680
+ self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
3681
+ yield
3689
3682
 
3683
+ except Exception as exc: # noqa
3684
+ if self._log:
3685
+ self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
3686
+ raise
3690
3687
 
3691
- def _subprocess_try_run(
3692
- fn: ta.Callable[..., T],
3693
- *args: ta.Any,
3694
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3695
- **kwargs: ta.Any,
3696
- ) -> ta.Union[T, Exception]:
3697
- try:
3698
- return fn(*args, **kwargs)
3699
- except try_exceptions as e: # noqa
3700
- if log.isEnabledFor(logging.DEBUG):
3701
- log.exception('command failed')
3702
- return e
3703
-
3704
-
3705
- def subprocess_try_call(
3706
- *args: str,
3707
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3708
- **kwargs: ta.Any,
3709
- ) -> bool:
3710
- if isinstance(_subprocess_try_run(
3711
- subprocess_check_call,
3712
- *args,
3713
- try_exceptions=try_exceptions,
3714
- **kwargs,
3715
- ), Exception):
3716
- return False
3717
- else:
3718
- return True
3688
+ finally:
3689
+ end_time = time.time()
3690
+ elapsed_s = end_time - start_time
3691
+ if self._log:
3692
+ self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
3719
3693
 
3694
+ @contextlib.contextmanager
3695
+ def prepare_and_wrap(
3696
+ self,
3697
+ *cmd: ta.Any,
3698
+ **kwargs: ta.Any,
3699
+ ) -> ta.Iterator[ta.Tuple[
3700
+ ta.Tuple[ta.Any, ...],
3701
+ ta.Dict[str, ta.Any],
3702
+ ]]:
3703
+ cmd, kwargs = self.prepare_args(*cmd, **kwargs)
3704
+ with self.wrap_call(*cmd, **kwargs):
3705
+ yield cmd, kwargs
3720
3706
 
3721
- def subprocess_try_output(
3722
- *args: str,
3723
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3724
- **kwargs: ta.Any,
3725
- ) -> ta.Optional[bytes]:
3726
- if isinstance(ret := _subprocess_try_run(
3727
- subprocess_check_output,
3728
- *args,
3729
- try_exceptions=try_exceptions,
3730
- **kwargs,
3731
- ), Exception):
3732
- return None
3733
- else:
3734
- return ret
3707
+ #
3708
+
3709
+ DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
3710
+ FileNotFoundError,
3711
+ subprocess.CalledProcessError,
3712
+ )
3735
3713
 
3714
+ def try_fn(
3715
+ self,
3716
+ fn: ta.Callable[..., T],
3717
+ *cmd: str,
3718
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3719
+ **kwargs: ta.Any,
3720
+ ) -> ta.Union[T, Exception]:
3721
+ if try_exceptions is None:
3722
+ try_exceptions = self._try_exceptions
3736
3723
 
3737
- def subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
3738
- out = subprocess_try_output(*args, **kwargs)
3739
- return out.decode().strip() if out is not None else None
3724
+ try:
3725
+ return fn(*cmd, **kwargs)
3726
+
3727
+ except try_exceptions as e: # noqa
3728
+ if self._log and self._log.isEnabledFor(logging.DEBUG):
3729
+ self._log.exception('command failed')
3730
+ return e
3731
+
3732
+ async def async_try_fn(
3733
+ self,
3734
+ fn: ta.Callable[..., ta.Awaitable[T]],
3735
+ *cmd: ta.Any,
3736
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3737
+ **kwargs: ta.Any,
3738
+ ) -> ta.Union[T, Exception]:
3739
+ if try_exceptions is None:
3740
+ try_exceptions = self._try_exceptions
3741
+
3742
+ try:
3743
+ return await fn(*cmd, **kwargs)
3744
+
3745
+ except try_exceptions as e: # noqa
3746
+ if self._log and self._log.isEnabledFor(logging.DEBUG):
3747
+ self._log.exception('command failed')
3748
+ return e
3740
3749
 
3741
3750
 
3742
3751
  ##
3743
3752
 
3744
3753
 
3745
- def subprocess_close(
3746
- proc: subprocess.Popen,
3747
- timeout: ta.Optional[float] = None,
3748
- ) -> None:
3749
- # TODO: terminate, sleep, kill
3750
- if proc.stdout:
3751
- proc.stdout.close()
3752
- if proc.stderr:
3753
- proc.stderr.close()
3754
- if proc.stdin:
3755
- proc.stdin.close()
3754
+ class Subprocesses(AbstractSubprocesses):
3755
+ def check_call(
3756
+ self,
3757
+ *cmd: str,
3758
+ stdout: ta.Any = sys.stderr,
3759
+ **kwargs: ta.Any,
3760
+ ) -> None:
3761
+ with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
3762
+ subprocess.check_call(cmd, **kwargs)
3756
3763
 
3757
- proc.wait(timeout)
3764
+ def check_output(
3765
+ self,
3766
+ *cmd: str,
3767
+ **kwargs: ta.Any,
3768
+ ) -> bytes:
3769
+ with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
3770
+ return subprocess.check_output(cmd, **kwargs)
3771
+
3772
+ def check_output_str(
3773
+ self,
3774
+ *cmd: str,
3775
+ **kwargs: ta.Any,
3776
+ ) -> str:
3777
+ return self.check_output(*cmd, **kwargs).decode().strip()
3778
+
3779
+ #
3780
+
3781
+ def try_call(
3782
+ self,
3783
+ *cmd: str,
3784
+ **kwargs: ta.Any,
3785
+ ) -> bool:
3786
+ if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
3787
+ return False
3788
+ else:
3789
+ return True
3790
+
3791
+ def try_output(
3792
+ self,
3793
+ *cmd: str,
3794
+ **kwargs: ta.Any,
3795
+ ) -> ta.Optional[bytes]:
3796
+ if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
3797
+ return None
3798
+ else:
3799
+ return ret
3800
+
3801
+ def try_output_str(
3802
+ self,
3803
+ *cmd: str,
3804
+ **kwargs: ta.Any,
3805
+ ) -> ta.Optional[str]:
3806
+ if (ret := self.try_output(*cmd, **kwargs)) is None:
3807
+ return None
3808
+ else:
3809
+ return ret.decode().strip()
3810
+
3811
+
3812
+ subprocesses = Subprocesses()
3758
3813
 
3759
3814
 
3760
3815
  ########################################