ominfra 0.0.0.dev156__tar.gz → 0.0.0.dev158__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. {ominfra-0.0.0.dev156/ominfra.egg-info → ominfra-0.0.0.dev158}/PKG-INFO +3 -3
  2. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/main.py +1 -1
  3. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/journald/tailer.py +2 -2
  4. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/bootstrap_.py +1 -1
  5. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/subprocess.py +4 -4
  6. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/apps.py +14 -15
  7. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/config.py +3 -0
  8. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/git.py +11 -27
  9. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/paths.py +48 -48
  10. ominfra-0.0.0.dev158/ominfra/manage/deploy/specs.py +32 -0
  11. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/venvs.py +10 -5
  12. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/main.py +33 -4
  13. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/spawning.py +4 -9
  14. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/packages.py +1 -1
  15. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/pyremote.py +26 -26
  16. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/scripts/journald2aws.py +469 -357
  17. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/scripts/manage.py +2488 -1463
  18. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/scripts/supervisor.py +385 -351
  19. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/configs.py +2 -0
  20. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/http.py +1 -1
  21. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/main.py +2 -2
  22. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/supervisor.py +2 -33
  23. ominfra-0.0.0.dev158/ominfra/supervisor/utils/os.py +86 -0
  24. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158/ominfra.egg-info}/PKG-INFO +3 -3
  25. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra.egg-info/SOURCES.txt +1 -0
  26. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra.egg-info/requires.txt +2 -2
  27. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/pyproject.toml +3 -3
  28. ominfra-0.0.0.dev156/ominfra/supervisor/utils/os.py +0 -45
  29. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/LICENSE +0 -0
  30. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/MANIFEST.in +0 -0
  31. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/README.rst +0 -0
  32. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/.manifests.json +0 -0
  33. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/__about__.py +0 -0
  34. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/__init__.py +0 -0
  35. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/__init__.py +0 -0
  36. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/__init__.py +0 -0
  37. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/__main__.py +0 -0
  38. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/auth.py +0 -0
  39. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/cli.py +0 -0
  40. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/dataclasses.py +0 -0
  41. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/__init__.py +0 -0
  42. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/__main__.py +0 -0
  43. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/cursor.py +0 -0
  44. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/driver.py +0 -0
  45. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/journald2aws/poster.py +0 -0
  46. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/logs.py +0 -0
  47. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/aws/metadata.py +0 -0
  48. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/gcp/__init__.py +0 -0
  49. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/clouds/gcp/auth.py +0 -0
  50. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/cmds.py +0 -0
  51. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/configs.py +0 -0
  52. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/journald/__init__.py +0 -0
  53. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/journald/fields.py +0 -0
  54. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/journald/genmessages.py +0 -0
  55. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/journald/messages.py +0 -0
  56. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/__init__.py +0 -0
  57. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/__main__.py +0 -0
  58. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/bootstrap.py +0 -0
  59. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/__init__.py +0 -0
  60. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/base.py +0 -0
  61. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/inject.py +0 -0
  62. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/local.py +0 -0
  63. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/marshal.py +0 -0
  64. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/ping.py +0 -0
  65. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/commands/types.py +0 -0
  66. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/config.py +0 -0
  67. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/__init__.py +0 -0
  68. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/commands.py +0 -0
  69. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/inject.py +0 -0
  70. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/interp.py +0 -0
  71. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/deploy/types.py +0 -0
  72. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/inject.py +0 -0
  73. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/marshal.py +0 -0
  74. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/__init__.py +0 -0
  75. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/_main.py +0 -0
  76. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/channel.py +0 -0
  77. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/config.py +0 -0
  78. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/connection.py +0 -0
  79. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/execution.py +0 -0
  80. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/inject.py +0 -0
  81. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/remote/payload.py +0 -0
  82. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/__init__.py +0 -0
  83. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/commands.py +0 -0
  84. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/config.py +0 -0
  85. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/inject.py +0 -0
  86. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/system/platforms.py +0 -0
  87. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/targets/__init__.py +0 -0
  88. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/targets/connection.py +0 -0
  89. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/targets/inject.py +0 -0
  90. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/manage/targets/targets.py +0 -0
  91. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/scripts/__init__.py +0 -0
  92. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/ssh.py +0 -0
  93. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/LICENSE.txt +0 -0
  94. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/__init__.py +0 -0
  95. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/__main__.py +0 -0
  96. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/dispatchers.py +0 -0
  97. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/dispatchersimpl.py +0 -0
  98. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/events.py +0 -0
  99. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/exceptions.py +0 -0
  100. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/groups.py +0 -0
  101. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/groupsimpl.py +0 -0
  102. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/inject.py +0 -0
  103. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/io.py +0 -0
  104. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/pipes.py +0 -0
  105. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/privileges.py +0 -0
  106. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/process.py +0 -0
  107. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/processimpl.py +0 -0
  108. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/setup.py +0 -0
  109. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/setupimpl.py +0 -0
  110. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/signals.py +0 -0
  111. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/spawning.py +0 -0
  112. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/spawningimpl.py +0 -0
  113. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/states.py +0 -0
  114. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/types.py +0 -0
  115. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/__init__.py +0 -0
  116. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/collections.py +0 -0
  117. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/diag.py +0 -0
  118. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/fds.py +0 -0
  119. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/fs.py +0 -0
  120. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/ostypes.py +0 -0
  121. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/signals.py +0 -0
  122. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/strings.py +0 -0
  123. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/supervisor/utils/users.py +0 -0
  124. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/tailscale/__init__.py +0 -0
  125. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/tailscale/api.py +0 -0
  126. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/tailscale/cli.py +0 -0
  127. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/threadworkers.py +0 -0
  128. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/tools/__init__.py +0 -0
  129. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra/tools/listresources.py +0 -0
  130. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra.egg-info/dependency_links.txt +0 -0
  131. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra.egg-info/entry_points.txt +0 -0
  132. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/ominfra.egg-info/top_level.txt +0 -0
  133. {ominfra-0.0.0.dev156 → ominfra-0.0.0.dev158}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev156
3
+ Version: 0.0.0.dev158
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.dev156
16
- Requires-Dist: omlish==0.0.0.dev156
15
+ Requires-Dist: omdev==0.0.0.dev158
16
+ Requires-Dist: omlish==0.0.0.dev158
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -5,7 +5,7 @@ import dataclasses as dc
5
5
  import os.path
6
6
  import sys
7
7
 
8
- from omlish.lite.logs import configure_standard_logging
8
+ from omlish.logs.standard import configure_standard_logging
9
9
 
10
10
  from ....configs import read_config_file
11
11
  from .driver import JournalctlToAwsDriver
@@ -410,8 +410,8 @@ import typing as ta
410
410
  from omlish.lite.cached import cached_nullary
411
411
  from omlish.lite.check import check
412
412
  from omlish.lite.logs import log
413
- from omlish.lite.subprocesses import subprocess_close
414
- from omlish.lite.subprocesses import subprocess_shell_wrap_exec
413
+ from omlish.subprocesses import subprocess_close
414
+ from omlish.subprocesses import subprocess_shell_wrap_exec
415
415
 
416
416
  from ..threadworkers import ThreadWorker
417
417
  from .messages import JournalctlMessage # noqa
@@ -1,7 +1,7 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  from omlish.lite.inject import Injector
3
3
  from omlish.lite.inject import inj
4
- from omlish.lite.logs import configure_standard_logging
4
+ from omlish.logs.standard import configure_standard_logging
5
5
 
6
6
  from .bootstrap import MainBootstrap
7
7
  from .inject import bind_main
@@ -6,11 +6,11 @@ import subprocess
6
6
  import time
7
7
  import typing as ta
8
8
 
9
- from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
9
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
10
10
  from omlish.lite.check import check
11
- from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
12
- from omlish.lite.subprocesses import SubprocessChannelOption
13
- from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
11
+ from omlish.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
12
+ from omlish.subprocesses import SubprocessChannelOption
13
+ from omlish.subprocesses import subprocess_maybe_shell_wrap_exec
14
14
 
15
15
  from .base import Command
16
16
  from .base import CommandExecutor
@@ -3,12 +3,13 @@ import datetime
3
3
  import os.path
4
4
  import typing as ta
5
5
 
6
+ from omlish.lite.cached import cached_nullary
7
+ from omlish.lite.check import check
8
+
6
9
  from .git import DeployGitManager
7
- from .git import DeployGitRepo
8
- from .git import DeployGitSpec
9
10
  from .paths import DeployPath
10
11
  from .paths import DeployPathOwner
11
- from .types import DeployApp
12
+ from .specs import DeploySpec
12
13
  from .types import DeployAppTag
13
14
  from .types import DeployHome
14
15
  from .types import DeployRev
@@ -24,14 +25,14 @@ def make_deploy_tag(
24
25
  now = datetime.datetime.utcnow() # noqa
25
26
  now_fmt = '%Y%m%dT%H%M%S'
26
27
  now_str = now.strftime(now_fmt)
27
- return DeployTag('-'.join([rev, now_str]))
28
+ return DeployTag('-'.join([now_str, rev]))
28
29
 
29
30
 
30
31
  class DeployAppManager(DeployPathOwner):
31
32
  def __init__(
32
33
  self,
33
34
  *,
34
- deploy_home: DeployHome,
35
+ deploy_home: ta.Optional[DeployHome] = None,
35
36
  git: DeployGitManager,
36
37
  venvs: DeployVenvManager,
37
38
  ) -> None:
@@ -41,7 +42,9 @@ class DeployAppManager(DeployPathOwner):
41
42
  self._git = git
42
43
  self._venvs = venvs
43
44
 
44
- self._dir = os.path.join(deploy_home, 'apps')
45
+ @cached_nullary
46
+ def _dir(self) -> str:
47
+ return os.path.join(check.non_empty_str(self._deploy_home), 'apps')
45
48
 
46
49
  def get_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
47
50
  return {
@@ -50,20 +53,16 @@ class DeployAppManager(DeployPathOwner):
50
53
 
51
54
  async def prepare_app(
52
55
  self,
53
- app: DeployApp,
54
- rev: DeployRev,
55
- repo: DeployGitRepo,
56
+ spec: DeploySpec,
56
57
  ):
57
- app_tag = DeployAppTag(app, make_deploy_tag(rev))
58
- app_dir = os.path.join(self._dir, app, app_tag.tag)
58
+ app_tag = DeployAppTag(spec.app, make_deploy_tag(spec.rev))
59
+ app_dir = os.path.join(self._dir(), spec.app, app_tag.tag)
59
60
 
60
61
  #
61
62
 
62
63
  await self._git.checkout(
63
- DeployGitSpec(
64
- repo=repo,
65
- rev=rev,
66
- ),
64
+ spec.repo,
65
+ spec.rev,
67
66
  app_dir,
68
67
  )
69
68
 
@@ -3,6 +3,9 @@ import dataclasses as dc
3
3
  import typing as ta
4
4
 
5
5
 
6
+ ##
7
+
8
+
6
9
  @dc.dataclass(frozen=True)
7
10
  class DeployConfig:
8
11
  deploy_home: ta.Optional[str] = None
@@ -8,17 +8,18 @@ git/github.com/wrmsr/omlish <- bootstrap repo
8
8
 
9
9
  github.com/wrmsr/omlish@rev
10
10
  """
11
- import dataclasses as dc
12
11
  import functools
13
12
  import os.path
14
13
  import typing as ta
15
14
 
16
- from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
15
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
17
16
  from omlish.lite.cached import async_cached_nullary
17
+ from omlish.lite.cached import cached_nullary
18
18
  from omlish.lite.check import check
19
19
 
20
20
  from .paths import DeployPath
21
21
  from .paths import DeployPathOwner
22
+ from .specs import DeployGitRepo
22
23
  from .types import DeployHome
23
24
  from .types import DeployRev
24
25
 
@@ -26,39 +27,22 @@ from .types import DeployRev
26
27
  ##
27
28
 
28
29
 
29
- @dc.dataclass(frozen=True)
30
- class DeployGitRepo:
31
- host: ta.Optional[str] = None
32
- username: ta.Optional[str] = None
33
- path: ta.Optional[str] = None
34
-
35
- def __post_init__(self) -> None:
36
- check.not_in('..', check.non_empty_str(self.host))
37
- check.not_in('.', check.non_empty_str(self.path))
38
-
39
-
40
- @dc.dataclass(frozen=True)
41
- class DeployGitSpec:
42
- repo: DeployGitRepo
43
- rev: DeployRev
44
-
45
-
46
- ##
47
-
48
-
49
30
  class DeployGitManager(DeployPathOwner):
50
31
  def __init__(
51
32
  self,
52
33
  *,
53
- deploy_home: DeployHome,
34
+ deploy_home: ta.Optional[DeployHome] = None,
54
35
  ) -> None:
55
36
  super().__init__()
56
37
 
57
38
  self._deploy_home = deploy_home
58
- self._dir = os.path.join(deploy_home, 'git')
59
39
 
60
40
  self._repo_dirs: ta.Dict[DeployGitRepo, DeployGitManager.RepoDir] = {}
61
41
 
42
+ @cached_nullary
43
+ def _dir(self) -> str:
44
+ return os.path.join(check.non_empty_str(self._deploy_home), 'git')
45
+
62
46
  def get_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
63
47
  return {
64
48
  DeployPath.parse('git'),
@@ -75,7 +59,7 @@ class DeployGitManager(DeployPathOwner):
75
59
  self._git = git
76
60
  self._repo = repo
77
61
  self._dir = os.path.join(
78
- self._git._dir, # noqa
62
+ self._git._dir(), # noqa
79
63
  check.non_empty_str(repo.host),
80
64
  check.non_empty_str(repo.path),
81
65
  )
@@ -132,5 +116,5 @@ class DeployGitManager(DeployPathOwner):
132
116
  repo_dir = self._repo_dirs[repo] = DeployGitManager.RepoDir(self, repo)
133
117
  return repo_dir
134
118
 
135
- async def checkout(self, spec: DeployGitSpec, dst_dir: str) -> None:
136
- await self.get_repo_dir(spec.repo).checkout(spec.rev, dst_dir)
119
+ async def checkout(self, repo: DeployGitRepo, rev: DeployRev, dst_dir: str) -> None:
120
+ await self.get_repo_dir(repo).checkout(rev, dst_dir)
@@ -3,22 +3,22 @@
3
3
  ~deploy
4
4
  deploy.pid (flock)
5
5
  /app
6
- /<appspec> - shallow clone
6
+ /<appplaceholder> - shallow clone
7
7
  /conf
8
8
  /env
9
- <appspec>.env
9
+ <appplaceholder>.env
10
10
  /nginx
11
- <appspec>.conf
11
+ <appplaceholder>.conf
12
12
  /supervisor
13
- <appspec>.conf
13
+ <appplaceholder>.conf
14
14
  /venv
15
- /<appspec>
15
+ /<appplaceholder>
16
16
 
17
17
  ?
18
18
  /logs
19
- /wrmsr--omlish--<spec>
19
+ /wrmsr--omlish--<placeholder>
20
20
 
21
- spec = <name>--<rev>--<when>
21
+ placeholder = <name>--<rev>--<when>
22
22
 
23
23
  ==
24
24
 
@@ -43,16 +43,16 @@ from omlish.lite.check import check
43
43
 
44
44
 
45
45
  DeployPathKind = ta.Literal['dir', 'file'] # ta.TypeAlias
46
- DeployPathSpec = ta.Literal['app', 'tag'] # ta.TypeAlias
46
+ DeployPathPlaceholder = ta.Literal['app', 'tag'] # ta.TypeAlias
47
47
 
48
48
 
49
49
  ##
50
50
 
51
51
 
52
- DEPLOY_PATH_SPEC_PLACEHOLDER = '@'
53
- DEPLOY_PATH_SPEC_SEPARATORS = '-.'
52
+ DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER = '@'
53
+ DEPLOY_PATH_PLACEHOLDER_SEPARATORS = '-.'
54
54
 
55
- DEPLOY_PATH_SPECS: ta.FrozenSet[str] = frozenset([
55
+ DEPLOY_PATH_PLACEHOLDERS: ta.FrozenSet[str] = frozenset([
56
56
  'app',
57
57
  'tag', # <rev>-<dt>
58
58
  ])
@@ -70,7 +70,7 @@ class DeployPathPart(abc.ABC): # noqa
70
70
  raise NotImplementedError
71
71
 
72
72
  @abc.abstractmethod
73
- def render(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
73
+ def render(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
74
74
  raise NotImplementedError
75
75
 
76
76
 
@@ -84,9 +84,9 @@ class DirDeployPathPart(DeployPathPart, abc.ABC):
84
84
 
85
85
  @classmethod
86
86
  def parse(cls, s: str) -> 'DirDeployPathPart':
87
- if DEPLOY_PATH_SPEC_PLACEHOLDER in s:
88
- check.equal(s[0], DEPLOY_PATH_SPEC_PLACEHOLDER)
89
- return SpecDirDeployPathPart(s[1:])
87
+ if DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER in s:
88
+ check.equal(s[0], DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER)
89
+ return PlaceholderDirDeployPathPart(s[1:])
90
90
  else:
91
91
  return ConstDirDeployPathPart(s)
92
92
 
@@ -98,13 +98,13 @@ class FileDeployPathPart(DeployPathPart, abc.ABC):
98
98
 
99
99
  @classmethod
100
100
  def parse(cls, s: str) -> 'FileDeployPathPart':
101
- if DEPLOY_PATH_SPEC_PLACEHOLDER in s:
102
- check.equal(s[0], DEPLOY_PATH_SPEC_PLACEHOLDER)
103
- if not any(c in s for c in DEPLOY_PATH_SPEC_SEPARATORS):
104
- return SpecFileDeployPathPart(s[1:], '')
101
+ if DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER in s:
102
+ check.equal(s[0], DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER)
103
+ if not any(c in s for c in DEPLOY_PATH_PLACEHOLDER_SEPARATORS):
104
+ return PlaceholderFileDeployPathPart(s[1:], '')
105
105
  else:
106
- p = min(f for c in DEPLOY_PATH_SPEC_SEPARATORS if (f := s.find(c)) > 0)
107
- return SpecFileDeployPathPart(s[1:p], s[p:])
106
+ p = min(f for c in DEPLOY_PATH_PLACEHOLDER_SEPARATORS if (f := s.find(c)) > 0)
107
+ return PlaceholderFileDeployPathPart(s[1:p], s[p:])
108
108
  else:
109
109
  return ConstFileDeployPathPart(s)
110
110
 
@@ -119,9 +119,9 @@ class ConstDeployPathPart(DeployPathPart, abc.ABC):
119
119
  def __post_init__(self) -> None:
120
120
  check.non_empty_str(self.name)
121
121
  check.not_in('/', self.name)
122
- check.not_in(DEPLOY_PATH_SPEC_PLACEHOLDER, self.name)
122
+ check.not_in(DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER, self.name)
123
123
 
124
- def render(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
124
+ def render(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
125
125
  return self.name
126
126
 
127
127
 
@@ -137,40 +137,40 @@ class ConstFileDeployPathPart(ConstDeployPathPart, FileDeployPathPart):
137
137
 
138
138
 
139
139
  @dc.dataclass(frozen=True)
140
- class SpecDeployPathPart(DeployPathPart, abc.ABC):
141
- spec: str # DeployPathSpec
140
+ class PlaceholderDeployPathPart(DeployPathPart, abc.ABC):
141
+ placeholder: str # DeployPathPlaceholder
142
142
 
143
143
  def __post_init__(self) -> None:
144
- check.non_empty_str(self.spec)
145
- for c in [*DEPLOY_PATH_SPEC_SEPARATORS, DEPLOY_PATH_SPEC_PLACEHOLDER, '/']:
146
- check.not_in(c, self.spec)
147
- check.in_(self.spec, DEPLOY_PATH_SPECS)
148
-
149
- def _render_spec(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
150
- if specs is not None:
151
- return specs[self.spec] # type: ignore
144
+ check.non_empty_str(self.placeholder)
145
+ for c in [*DEPLOY_PATH_PLACEHOLDER_SEPARATORS, DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER, '/']:
146
+ check.not_in(c, self.placeholder)
147
+ check.in_(self.placeholder, DEPLOY_PATH_PLACEHOLDERS)
148
+
149
+ def _render_placeholder(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
150
+ if placeholders is not None:
151
+ return placeholders[self.placeholder] # type: ignore
152
152
  else:
153
- return DEPLOY_PATH_SPEC_PLACEHOLDER + self.spec
153
+ return DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER + self.placeholder
154
154
 
155
155
 
156
156
  @dc.dataclass(frozen=True)
157
- class SpecDirDeployPathPart(SpecDeployPathPart, DirDeployPathPart):
158
- def render(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
159
- return self._render_spec(specs)
157
+ class PlaceholderDirDeployPathPart(PlaceholderDeployPathPart, DirDeployPathPart):
158
+ def render(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
159
+ return self._render_placeholder(placeholders)
160
160
 
161
161
 
162
162
  @dc.dataclass(frozen=True)
163
- class SpecFileDeployPathPart(SpecDeployPathPart, FileDeployPathPart):
163
+ class PlaceholderFileDeployPathPart(PlaceholderDeployPathPart, FileDeployPathPart):
164
164
  suffix: str
165
165
 
166
166
  def __post_init__(self) -> None:
167
167
  super().__post_init__()
168
168
  if self.suffix:
169
- for c in [DEPLOY_PATH_SPEC_PLACEHOLDER, '/']:
169
+ for c in [DEPLOY_PATH_PLACEHOLDER_PLACEHOLDER, '/']:
170
170
  check.not_in(c, self.suffix)
171
171
 
172
- def render(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
173
- return self._render_spec(specs) + self.suffix
172
+ def render(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
173
+ return self._render_placeholder(placeholders) + self.suffix
174
174
 
175
175
 
176
176
  ##
@@ -187,22 +187,22 @@ class DeployPath:
187
187
 
188
188
  pd = {}
189
189
  for i, p in enumerate(self.parts):
190
- if isinstance(p, SpecDeployPathPart):
191
- if p.spec in pd:
192
- raise DeployPathError('Duplicate specs in path', self)
193
- pd[p.spec] = i
190
+ if isinstance(p, PlaceholderDeployPathPart):
191
+ if p.placeholder in pd:
192
+ raise DeployPathError('Duplicate placeholders in path', self)
193
+ pd[p.placeholder] = i
194
194
 
195
195
  if 'tag' in pd:
196
196
  if 'app' not in pd or pd['app'] >= pd['tag']:
197
- raise DeployPathError('Tag spec in path without preceding app', self)
197
+ raise DeployPathError('Tag placeholder in path without preceding app', self)
198
198
 
199
199
  @property
200
200
  def kind(self) -> ta.Literal['file', 'dir']:
201
201
  return self.parts[-1].kind
202
202
 
203
- def render(self, specs: ta.Optional[ta.Mapping[DeployPathSpec, str]] = None) -> str:
203
+ def render(self, placeholders: ta.Optional[ta.Mapping[DeployPathPlaceholder, str]] = None) -> str:
204
204
  return os.path.join( # noqa
205
- *[p.render(specs) for p in self.parts],
205
+ *[p.render(placeholders) for p in self.parts],
206
206
  *([''] if self.kind == 'dir' else []),
207
207
  )
208
208
 
@@ -0,0 +1,32 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+ from omlish.lite.check import check
6
+
7
+ from .types import DeployApp
8
+ from .types import DeployRev
9
+
10
+
11
+ ##
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class DeployGitRepo:
16
+ host: ta.Optional[str] = None
17
+ username: ta.Optional[str] = None
18
+ path: ta.Optional[str] = None
19
+
20
+ def __post_init__(self) -> None:
21
+ check.not_in('..', check.non_empty_str(self.host))
22
+ check.not_in('.', check.non_empty_str(self.path))
23
+
24
+
25
+ ##
26
+
27
+
28
+ @dc.dataclass(frozen=True)
29
+ class DeploySpec:
30
+ app: DeployApp
31
+ repo: DeployGitRepo
32
+ rev: DeployRev
@@ -7,7 +7,9 @@ TODO:
7
7
  import os.path
8
8
  import typing as ta
9
9
 
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
10
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
11
+ from omlish.lite.cached import cached_nullary
12
+ from omlish.lite.check import check
11
13
 
12
14
  from .paths import DeployPath
13
15
  from .paths import DeployPathOwner
@@ -19,12 +21,15 @@ class DeployVenvManager(DeployPathOwner):
19
21
  def __init__(
20
22
  self,
21
23
  *,
22
- deploy_home: DeployHome,
24
+ deploy_home: ta.Optional[DeployHome] = None,
23
25
  ) -> None:
24
26
  super().__init__()
25
27
 
26
28
  self._deploy_home = deploy_home
27
- self._dir = os.path.join(deploy_home, 'venvs')
29
+
30
+ @cached_nullary
31
+ def _dir(self) -> str:
32
+ return os.path.join(check.non_empty_str(self._deploy_home), 'venvs')
28
33
 
29
34
  def get_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
30
35
  return {
@@ -61,6 +66,6 @@ class DeployVenvManager(DeployPathOwner):
61
66
 
62
67
  async def setup_app_venv(self, app_tag: DeployAppTag) -> None:
63
68
  await self.setup_venv(
64
- os.path.join(self._deploy_home, 'apps', app_tag.app, app_tag.tag),
65
- os.path.join(self._deploy_home, 'venvs', app_tag.app, app_tag.tag),
69
+ os.path.join(check.non_empty_str(self._deploy_home), 'apps', app_tag.app, app_tag.tag),
70
+ os.path.join(self._dir(), app_tag.app, app_tag.tag),
66
71
  )
@@ -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_subprocesses
10
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
11
11
  from omlish.lite.check import check
12
- from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
- from omlish.lite.subprocesses import SubprocessChannelOption
14
- from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
12
+ from omlish.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
+ from omlish.subprocesses import SubprocessChannelOption
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
84
  async with asyncio_subprocesses.popen(
90
- *cmd,
85
+ *pc.cmd,
91
86
  shell=pc.shell,
92
87
  stdin=subprocess.PIPE,
93
88
  stdout=subprocess.PIPE,
@@ -9,7 +9,7 @@ import json
9
9
  import os
10
10
  import typing as ta
11
11
 
12
- from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
12
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
13
13
  from omlish.lite.check import check
14
14
 
15
15