ominfra 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev156__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ominfra/manage/bootstrap.py +4 -0
- ominfra/manage/bootstrap_.py +5 -0
- ominfra/manage/commands/inject.py +8 -11
- ominfra/manage/commands/{execution.py → local.py} +1 -5
- ominfra/manage/commands/ping.py +23 -0
- ominfra/manage/commands/subprocess.py +3 -4
- ominfra/manage/commands/types.py +8 -0
- ominfra/manage/deploy/apps.py +72 -0
- ominfra/manage/deploy/config.py +8 -0
- ominfra/manage/deploy/git.py +136 -0
- ominfra/manage/deploy/inject.py +21 -0
- ominfra/manage/deploy/paths.py +81 -28
- ominfra/manage/deploy/types.py +13 -0
- ominfra/manage/deploy/venvs.py +66 -0
- ominfra/manage/inject.py +20 -4
- ominfra/manage/main.py +15 -27
- ominfra/manage/remote/_main.py +1 -1
- ominfra/manage/remote/config.py +0 -2
- ominfra/manage/remote/connection.py +7 -24
- ominfra/manage/remote/execution.py +1 -1
- ominfra/manage/remote/inject.py +3 -14
- ominfra/manage/remote/spawning.py +2 -2
- ominfra/manage/system/commands.py +22 -2
- ominfra/manage/system/config.py +3 -1
- ominfra/manage/system/inject.py +16 -6
- ominfra/manage/system/packages.py +38 -14
- ominfra/manage/system/platforms.py +72 -0
- ominfra/manage/targets/__init__.py +0 -0
- ominfra/manage/targets/connection.py +150 -0
- ominfra/manage/targets/inject.py +42 -0
- ominfra/manage/targets/targets.py +87 -0
- ominfra/scripts/journald2aws.py +205 -134
- ominfra/scripts/manage.py +2192 -734
- ominfra/scripts/supervisor.py +187 -25
- ominfra/supervisor/configs.py +163 -18
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/RECORD +42 -31
- ominfra/manage/system/types.py +0 -5
- /ominfra/manage/{commands → deploy}/interp.py +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev156.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
"""
|
3
|
+
TODO:
|
4
|
+
- interp
|
5
|
+
- share more code with pyproject?
|
6
|
+
"""
|
7
|
+
import os.path
|
8
|
+
import typing as ta
|
9
|
+
|
10
|
+
from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
|
11
|
+
|
12
|
+
from .paths import DeployPath
|
13
|
+
from .paths import DeployPathOwner
|
14
|
+
from .types import DeployAppTag
|
15
|
+
from .types import DeployHome
|
16
|
+
|
17
|
+
|
18
|
+
class DeployVenvManager(DeployPathOwner):
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
*,
|
22
|
+
deploy_home: DeployHome,
|
23
|
+
) -> None:
|
24
|
+
super().__init__()
|
25
|
+
|
26
|
+
self._deploy_home = deploy_home
|
27
|
+
self._dir = os.path.join(deploy_home, 'venvs')
|
28
|
+
|
29
|
+
def get_deploy_paths(self) -> ta.AbstractSet[DeployPath]:
|
30
|
+
return {
|
31
|
+
DeployPath.parse('venvs/@app/@tag/'),
|
32
|
+
}
|
33
|
+
|
34
|
+
async def setup_venv(
|
35
|
+
self,
|
36
|
+
app_dir: str,
|
37
|
+
venv_dir: str,
|
38
|
+
*,
|
39
|
+
use_uv: bool = True,
|
40
|
+
) -> None:
|
41
|
+
sys_exe = 'python3'
|
42
|
+
|
43
|
+
await asyncio_subprocesses.check_call(sys_exe, '-m', 'venv', venv_dir)
|
44
|
+
|
45
|
+
#
|
46
|
+
|
47
|
+
venv_exe = os.path.join(venv_dir, 'bin', 'python3')
|
48
|
+
|
49
|
+
#
|
50
|
+
|
51
|
+
reqs_txt = os.path.join(app_dir, 'requirements.txt')
|
52
|
+
|
53
|
+
if os.path.isfile(reqs_txt):
|
54
|
+
if use_uv:
|
55
|
+
await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
|
56
|
+
pip_cmd = ['-m', 'uv', 'pip']
|
57
|
+
else:
|
58
|
+
pip_cmd = ['-m', 'pip']
|
59
|
+
|
60
|
+
await asyncio_subprocesses.check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
|
61
|
+
|
62
|
+
async def setup_app_venv(self, app_tag: DeployAppTag) -> None:
|
63
|
+
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),
|
66
|
+
)
|
ominfra/manage/inject.py
CHANGED
@@ -6,8 +6,10 @@ from omlish.lite.inject import InjectorBindings
|
|
6
6
|
from omlish.lite.inject import inj
|
7
7
|
from omlish.lite.marshal import ObjMarshalerManager
|
8
8
|
|
9
|
+
from .bootstrap import MainBootstrap
|
9
10
|
from .commands.inject import bind_commands
|
10
11
|
from .config import MainConfig
|
12
|
+
from .deploy.config import DeployConfig
|
11
13
|
from .deploy.inject import bind_deploy
|
12
14
|
from .marshal import ObjMarshalerInstaller
|
13
15
|
from .marshal import ObjMarshalerInstallers
|
@@ -15,6 +17,7 @@ from .remote.config import RemoteConfig
|
|
15
17
|
from .remote.inject import bind_remote
|
16
18
|
from .system.config import SystemConfig
|
17
19
|
from .system.inject import bind_system
|
20
|
+
from .targets.inject import bind_targets
|
18
21
|
|
19
22
|
|
20
23
|
##
|
@@ -22,9 +25,13 @@ from .system.inject import bind_system
|
|
22
25
|
|
23
26
|
def bind_main(
|
24
27
|
*,
|
25
|
-
main_config: MainConfig,
|
26
|
-
|
27
|
-
|
28
|
+
main_config: MainConfig = MainConfig(),
|
29
|
+
|
30
|
+
deploy_config: DeployConfig = DeployConfig(),
|
31
|
+
remote_config: RemoteConfig = RemoteConfig(),
|
32
|
+
system_config: SystemConfig = SystemConfig(),
|
33
|
+
|
34
|
+
main_bootstrap: ta.Optional[MainBootstrap] = None,
|
28
35
|
) -> InjectorBindings:
|
29
36
|
lst: ta.List[InjectorBindingOrBindings] = [
|
30
37
|
inj.bind(main_config),
|
@@ -33,7 +40,9 @@ def bind_main(
|
|
33
40
|
main_config=main_config,
|
34
41
|
),
|
35
42
|
|
36
|
-
bind_deploy(
|
43
|
+
bind_deploy(
|
44
|
+
deploy_config=deploy_config,
|
45
|
+
),
|
37
46
|
|
38
47
|
bind_remote(
|
39
48
|
remote_config=remote_config,
|
@@ -42,10 +51,17 @@ def bind_main(
|
|
42
51
|
bind_system(
|
43
52
|
system_config=system_config,
|
44
53
|
),
|
54
|
+
|
55
|
+
bind_targets(),
|
45
56
|
]
|
46
57
|
|
47
58
|
#
|
48
59
|
|
60
|
+
if main_bootstrap is not None:
|
61
|
+
lst.append(inj.bind(main_bootstrap))
|
62
|
+
|
63
|
+
#
|
64
|
+
|
49
65
|
def build_obj_marshaler_manager(insts: ObjMarshalerInstallers) -> ObjMarshalerManager:
|
50
66
|
msh = ObjMarshalerManager()
|
51
67
|
inst: ObjMarshalerInstaller
|
ominfra/manage/main.py
CHANGED
@@ -6,7 +6,6 @@ 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 contextlib
|
10
9
|
import json
|
11
10
|
import sys
|
12
11
|
import typing as ta
|
@@ -22,22 +21,17 @@ from omlish.lite.pycharm import PycharmRemoteDebug
|
|
22
21
|
from .bootstrap import MainBootstrap
|
23
22
|
from .bootstrap_ import main_bootstrap
|
24
23
|
from .commands.base import Command
|
25
|
-
from .commands.base import CommandExecutor
|
26
|
-
from .commands.execution import LocalCommandExecutor
|
27
24
|
from .config import MainConfig
|
25
|
+
from .deploy.config import DeployConfig
|
28
26
|
from .remote.config import RemoteConfig
|
29
|
-
from .
|
30
|
-
from .
|
27
|
+
from .targets.connection import ManageTargetConnector
|
28
|
+
from .targets.targets import ManageTarget
|
31
29
|
|
32
30
|
|
33
31
|
class MainCli(ArgparseCli):
|
34
32
|
@argparse_command(
|
35
33
|
argparse_arg('--_payload-file'),
|
36
34
|
|
37
|
-
argparse_arg('-s', '--shell'),
|
38
|
-
argparse_arg('-q', '--shell-quote', action='store_true'),
|
39
|
-
argparse_arg('--python', default='python3'),
|
40
|
-
|
41
35
|
argparse_arg('--pycharm-debug-port', type=int),
|
42
36
|
argparse_arg('--pycharm-debug-host'),
|
43
37
|
argparse_arg('--pycharm-debug-version'),
|
@@ -46,8 +40,9 @@ class MainCli(ArgparseCli):
|
|
46
40
|
|
47
41
|
argparse_arg('--debug', action='store_true'),
|
48
42
|
|
49
|
-
argparse_arg('--
|
43
|
+
argparse_arg('--deploy-home'),
|
50
44
|
|
45
|
+
argparse_arg('target'),
|
51
46
|
argparse_arg('command', nargs='+'),
|
52
47
|
)
|
53
48
|
async def run(self) -> None:
|
@@ -58,6 +53,10 @@ class MainCli(ArgparseCli):
|
|
58
53
|
debug=bool(self.args.debug),
|
59
54
|
),
|
60
55
|
|
56
|
+
deploy_config=DeployConfig(
|
57
|
+
deploy_home=self.args.deploy_home,
|
58
|
+
),
|
59
|
+
|
61
60
|
remote_config=RemoteConfig(
|
62
61
|
payload_file=self.args._payload_file, # noqa
|
63
62
|
|
@@ -68,8 +67,6 @@ class MainCli(ArgparseCli):
|
|
68
67
|
) if self.args.pycharm_debug_port is not None else None,
|
69
68
|
|
70
69
|
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
71
|
-
|
72
|
-
use_in_process_remote_executor=True,
|
73
70
|
),
|
74
71
|
)
|
75
72
|
|
@@ -83,6 +80,11 @@ class MainCli(ArgparseCli):
|
|
83
80
|
|
84
81
|
msh = injector[ObjMarshalerManager]
|
85
82
|
|
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)
|
87
|
+
|
86
88
|
cmds: ta.List[Command] = []
|
87
89
|
cmd: Command
|
88
90
|
for c in self.args.command:
|
@@ -93,21 +95,7 @@ class MainCli(ArgparseCli):
|
|
93
95
|
|
94
96
|
#
|
95
97
|
|
96
|
-
async with
|
97
|
-
ce: CommandExecutor
|
98
|
-
|
99
|
-
if self.args.local:
|
100
|
-
ce = injector[LocalCommandExecutor]
|
101
|
-
|
102
|
-
else:
|
103
|
-
tgt = RemoteSpawning.Target(
|
104
|
-
shell=self.args.shell,
|
105
|
-
shell_quote=self.args.shell_quote,
|
106
|
-
python=self.args.python,
|
107
|
-
)
|
108
|
-
|
109
|
-
ce = await es.enter_async_context(injector[RemoteExecutionConnector].connect(tgt, bs)) # noqa
|
110
|
-
|
98
|
+
async with injector[ManageTargetConnector].connect(tgt) as ce:
|
111
99
|
async def run_command(cmd: Command) -> None:
|
112
100
|
res = await ce.try_execute(
|
113
101
|
cmd,
|
ominfra/manage/remote/_main.py
CHANGED
@@ -20,7 +20,7 @@ from omlish.os.deathsig import set_process_deathsig
|
|
20
20
|
|
21
21
|
from ...pyremote import pyremote_bootstrap_finalize
|
22
22
|
from ..bootstrap import MainBootstrap
|
23
|
-
from ..commands.
|
23
|
+
from ..commands.local import LocalCommandExecutor
|
24
24
|
from .channel import RemoteChannel
|
25
25
|
from .channel import RemoteChannelImpl
|
26
26
|
from .execution import _RemoteCommandHandler
|
ominfra/manage/remote/config.py
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
-
import abc
|
3
2
|
import asyncio
|
4
3
|
import contextlib
|
5
4
|
import typing as ta
|
6
5
|
|
7
6
|
from omlish.asyncs.asyncio.channels import asyncio_create_bytes_channel
|
8
7
|
from omlish.lite.cached import cached_nullary
|
8
|
+
from omlish.lite.contextmanagers import aclosing
|
9
9
|
from omlish.lite.marshal import ObjMarshalerManager
|
10
10
|
|
11
11
|
from ...pyremote import PyremoteBootstrapDriver
|
12
12
|
from ...pyremote import PyremoteBootstrapOptions
|
13
13
|
from ...pyremote import pyremote_build_bootstrap_cmd
|
14
14
|
from ..bootstrap import MainBootstrap
|
15
|
-
from ..commands.
|
15
|
+
from ..commands.local import LocalCommandExecutor
|
16
16
|
from ._main import _remote_execution_main # noqa
|
17
17
|
from .channel import RemoteChannelImpl
|
18
18
|
from .execution import RemoteCommandExecutor
|
@@ -25,20 +25,7 @@ from .spawning import RemoteSpawning
|
|
25
25
|
##
|
26
26
|
|
27
27
|
|
28
|
-
class
|
29
|
-
@abc.abstractmethod
|
30
|
-
def connect(
|
31
|
-
self,
|
32
|
-
tgt: RemoteSpawning.Target,
|
33
|
-
bs: MainBootstrap,
|
34
|
-
) -> ta.AsyncContextManager[RemoteCommandExecutor]:
|
35
|
-
raise NotImplementedError
|
36
|
-
|
37
|
-
|
38
|
-
##
|
39
|
-
|
40
|
-
|
41
|
-
class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
28
|
+
class PyremoteRemoteExecutionConnector:
|
42
29
|
def __init__(
|
43
30
|
self,
|
44
31
|
*,
|
@@ -104,7 +91,7 @@ class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
|
104
91
|
await chan.send_obj(bs)
|
105
92
|
|
106
93
|
rce: RemoteCommandExecutor
|
107
|
-
async with
|
94
|
+
async with aclosing(RemoteCommandExecutor(chan)) as rce:
|
108
95
|
await rce.start()
|
109
96
|
|
110
97
|
yield rce
|
@@ -113,7 +100,7 @@ class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
|
113
100
|
##
|
114
101
|
|
115
102
|
|
116
|
-
class InProcessRemoteExecutionConnector
|
103
|
+
class InProcessRemoteExecutionConnector:
|
117
104
|
def __init__(
|
118
105
|
self,
|
119
106
|
*,
|
@@ -126,11 +113,7 @@ class InProcessRemoteExecutionConnector(RemoteExecutionConnector):
|
|
126
113
|
self._local_executor = local_executor
|
127
114
|
|
128
115
|
@contextlib.asynccontextmanager
|
129
|
-
async def connect(
|
130
|
-
self,
|
131
|
-
tgt: RemoteSpawning.Target,
|
132
|
-
bs: MainBootstrap,
|
133
|
-
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
116
|
+
async def connect(self) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
134
117
|
r0, w0 = asyncio_create_bytes_channel()
|
135
118
|
r1, w1 = asyncio_create_bytes_channel()
|
136
119
|
|
@@ -144,7 +127,7 @@ class InProcessRemoteExecutionConnector(RemoteExecutionConnector):
|
|
144
127
|
rch_task = asyncio.create_task(rch.run()) # noqa
|
145
128
|
try:
|
146
129
|
rce: RemoteCommandExecutor
|
147
|
-
async with
|
130
|
+
async with aclosing(RemoteCommandExecutor(local_chan)) as rce:
|
148
131
|
await rce.start()
|
149
132
|
|
150
133
|
yield rce
|
@@ -394,7 +394,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
394
394
|
self,
|
395
395
|
cmd: Command,
|
396
396
|
*,
|
397
|
-
log: ta.Optional[logging.Logger] = None,
|
397
|
+
log: ta.Optional[logging.Logger] = None, # noqa
|
398
398
|
omit_exc_object: bool = False,
|
399
399
|
) -> CommandOutputOrException:
|
400
400
|
try:
|
ominfra/manage/remote/inject.py
CHANGED
@@ -8,7 +8,6 @@ from omlish.lite.inject import inj
|
|
8
8
|
from .config import RemoteConfig
|
9
9
|
from .connection import InProcessRemoteExecutionConnector
|
10
10
|
from .connection import PyremoteRemoteExecutionConnector
|
11
|
-
from .connection import RemoteExecutionConnector
|
12
11
|
from .payload import RemoteExecutionPayloadFile
|
13
12
|
from .spawning import RemoteSpawning
|
14
13
|
from .spawning import SubprocessRemoteSpawning
|
@@ -23,20 +22,10 @@ def bind_remote(
|
|
23
22
|
|
24
23
|
inj.bind(SubprocessRemoteSpawning, singleton=True),
|
25
24
|
inj.bind(RemoteSpawning, to_key=SubprocessRemoteSpawning),
|
26
|
-
]
|
27
|
-
|
28
|
-
#
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
inj.bind(RemoteExecutionConnector, to_key=InProcessRemoteExecutionConnector),
|
34
|
-
])
|
35
|
-
else:
|
36
|
-
lst.extend([
|
37
|
-
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
38
|
-
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
39
|
-
])
|
26
|
+
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
27
|
+
inj.bind(InProcessRemoteExecutionConnector, singleton=True),
|
28
|
+
]
|
40
29
|
|
41
30
|
#
|
42
31
|
|
@@ -7,7 +7,7 @@ import shlex
|
|
7
7
|
import subprocess
|
8
8
|
import typing as ta
|
9
9
|
|
10
|
-
from omlish.lite.asyncio.subprocesses import
|
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
|
@@ -86,7 +86,7 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
86
86
|
if not debug:
|
87
87
|
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
88
88
|
|
89
|
-
async with
|
89
|
+
async with asyncio_subprocesses.popen(
|
90
90
|
*cmd,
|
91
91
|
shell=pc.shell,
|
92
92
|
stdin=subprocess.PIPE,
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
import dataclasses as dc
|
3
|
+
import typing as ta
|
3
4
|
|
5
|
+
from omlish.lite.check import check
|
4
6
|
from omlish.lite.logs import log
|
5
7
|
|
6
8
|
from ..commands.base import Command
|
7
9
|
from ..commands.base import CommandExecutor
|
10
|
+
from .packages import SystemPackage
|
11
|
+
from .packages import SystemPackageManager
|
8
12
|
|
9
13
|
|
10
14
|
##
|
@@ -12,13 +16,29 @@ from ..commands.base import CommandExecutor
|
|
12
16
|
|
13
17
|
@dc.dataclass(frozen=True)
|
14
18
|
class CheckSystemPackageCommand(Command['CheckSystemPackageCommand.Output']):
|
19
|
+
pkgs: ta.Sequence[str] = ()
|
20
|
+
|
21
|
+
def __post_init__(self) -> None:
|
22
|
+
check.not_isinstance(self.pkgs, str)
|
23
|
+
|
15
24
|
@dc.dataclass(frozen=True)
|
16
25
|
class Output(Command.Output):
|
17
|
-
|
26
|
+
pkgs: ta.Sequence[SystemPackage]
|
18
27
|
|
19
28
|
|
20
29
|
class CheckSystemPackageCommandExecutor(CommandExecutor[CheckSystemPackageCommand, CheckSystemPackageCommand.Output]):
|
30
|
+
def __init__(
|
31
|
+
self,
|
32
|
+
*,
|
33
|
+
mgr: SystemPackageManager,
|
34
|
+
) -> None:
|
35
|
+
super().__init__()
|
36
|
+
|
37
|
+
self._mgr = mgr
|
38
|
+
|
21
39
|
async def execute(self, cmd: CheckSystemPackageCommand) -> CheckSystemPackageCommand.Output:
|
22
40
|
log.info('Checking system package!')
|
23
41
|
|
24
|
-
|
42
|
+
ret = await self._mgr.query(*cmd.pkgs)
|
43
|
+
|
44
|
+
return CheckSystemPackageCommand.Output(list(ret.values()))
|
ominfra/manage/system/config.py
CHANGED
ominfra/manage/system/inject.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
-
import sys
|
3
2
|
import typing as ta
|
4
3
|
|
5
4
|
from omlish.lite.inject import InjectorBindingOrBindings
|
@@ -13,7 +12,12 @@ from .config import SystemConfig
|
|
13
12
|
from .packages import AptSystemPackageManager
|
14
13
|
from .packages import BrewSystemPackageManager
|
15
14
|
from .packages import SystemPackageManager
|
16
|
-
from .
|
15
|
+
from .packages import YumSystemPackageManager
|
16
|
+
from .platforms import AmazonLinuxPlatform
|
17
|
+
from .platforms import DarwinPlatform
|
18
|
+
from .platforms import LinuxPlatform
|
19
|
+
from .platforms import Platform
|
20
|
+
from .platforms import detect_system_platform
|
17
21
|
|
18
22
|
|
19
23
|
def bind_system(
|
@@ -26,18 +30,24 @@ def bind_system(
|
|
26
30
|
|
27
31
|
#
|
28
32
|
|
29
|
-
platform = system_config.platform or
|
30
|
-
lst.append(inj.bind(platform, key=
|
33
|
+
platform = system_config.platform or detect_system_platform()
|
34
|
+
lst.append(inj.bind(platform, key=Platform))
|
31
35
|
|
32
36
|
#
|
33
37
|
|
34
|
-
if platform
|
38
|
+
if isinstance(platform, AmazonLinuxPlatform):
|
39
|
+
lst.extend([
|
40
|
+
inj.bind(YumSystemPackageManager, singleton=True),
|
41
|
+
inj.bind(SystemPackageManager, to_key=YumSystemPackageManager),
|
42
|
+
])
|
43
|
+
|
44
|
+
elif isinstance(platform, LinuxPlatform):
|
35
45
|
lst.extend([
|
36
46
|
inj.bind(AptSystemPackageManager, singleton=True),
|
37
47
|
inj.bind(SystemPackageManager, to_key=AptSystemPackageManager),
|
38
48
|
])
|
39
49
|
|
40
|
-
elif platform
|
50
|
+
elif isinstance(platform, DarwinPlatform):
|
41
51
|
lst.extend([
|
42
52
|
inj.bind(BrewSystemPackageManager, singleton=True),
|
43
53
|
inj.bind(SystemPackageManager, to_key=BrewSystemPackageManager),
|
@@ -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
|
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
|
45
|
+
await asyncio_subprocesses.check_call('brew', 'update')
|
48
46
|
|
49
47
|
async def upgrade(self) -> None:
|
50
|
-
await
|
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
|
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
|
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,28 +77,54 @@ class AptSystemPackageManager(SystemPackageManager):
|
|
79
77
|
}
|
80
78
|
|
81
79
|
async def update(self) -> None:
|
82
|
-
await
|
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
|
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
|
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
|
-
|
94
|
-
|
95
|
-
*cmd,
|
91
|
+
out = await asyncio_subprocesses.run(
|
92
|
+
'dpkg-query', '-W', '-f=${Package}=${Version}\n', *pns,
|
96
93
|
capture_output=True,
|
97
94
|
check=False,
|
98
95
|
)
|
99
96
|
d: ta.Dict[str, SystemPackage] = {}
|
100
|
-
for l in check.not_none(stdout).decode('utf-8').strip().splitlines():
|
97
|
+
for l in check.not_none(out.stdout).decode('utf-8').strip().splitlines():
|
101
98
|
n, v = l.split('=', 1)
|
102
99
|
d[n] = SystemPackage(
|
103
100
|
name=n,
|
104
101
|
version=v,
|
105
102
|
)
|
106
103
|
return d
|
104
|
+
|
105
|
+
|
106
|
+
class YumSystemPackageManager(SystemPackageManager):
|
107
|
+
async def update(self) -> None:
|
108
|
+
await asyncio_subprocesses.check_call('sudo', 'yum', 'check-update')
|
109
|
+
|
110
|
+
async def upgrade(self) -> None:
|
111
|
+
await asyncio_subprocesses.check_call('sudo', 'yum', 'update')
|
112
|
+
|
113
|
+
async def install(self, *packages: SystemPackageOrStr) -> None:
|
114
|
+
pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
|
115
|
+
await asyncio_subprocesses.check_call('sudo', 'yum', 'install', *pns)
|
116
|
+
|
117
|
+
async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
|
118
|
+
pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
|
119
|
+
d: ta.Dict[str, SystemPackage] = {}
|
120
|
+
for pn in pns:
|
121
|
+
out = await asyncio_subprocesses.run(
|
122
|
+
'rpm', '-q', pn,
|
123
|
+
capture_output=True,
|
124
|
+
)
|
125
|
+
if not out.proc.returncode:
|
126
|
+
d[pn] = SystemPackage(
|
127
|
+
pn,
|
128
|
+
check.not_none(out.stdout).decode().strip(),
|
129
|
+
)
|
130
|
+
return d
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import abc
|
2
|
+
import dataclasses as dc
|
3
|
+
import sys
|
4
|
+
|
5
|
+
from omlish.lite.cached import cached_nullary
|
6
|
+
from omlish.lite.logs import log
|
7
|
+
from omlish.os.linux import LinuxOsRelease
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
@dc.dataclass(frozen=True)
|
14
|
+
class Platform(abc.ABC): # noqa
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
class LinuxPlatform(Platform, abc.ABC):
|
19
|
+
pass
|
20
|
+
|
21
|
+
|
22
|
+
class UbuntuPlatform(LinuxPlatform):
|
23
|
+
pass
|
24
|
+
|
25
|
+
|
26
|
+
class AmazonLinuxPlatform(LinuxPlatform):
|
27
|
+
pass
|
28
|
+
|
29
|
+
|
30
|
+
class GenericLinuxPlatform(LinuxPlatform):
|
31
|
+
pass
|
32
|
+
|
33
|
+
|
34
|
+
class DarwinPlatform(Platform):
|
35
|
+
pass
|
36
|
+
|
37
|
+
|
38
|
+
class UnknownPlatform(Platform):
|
39
|
+
pass
|
40
|
+
|
41
|
+
|
42
|
+
##
|
43
|
+
|
44
|
+
|
45
|
+
def _detect_system_platform() -> Platform:
|
46
|
+
plat = sys.platform
|
47
|
+
|
48
|
+
if plat == 'linux':
|
49
|
+
if (osr := LinuxOsRelease.read()) is None:
|
50
|
+
return GenericLinuxPlatform()
|
51
|
+
|
52
|
+
if osr.id == 'amzn':
|
53
|
+
return AmazonLinuxPlatform()
|
54
|
+
|
55
|
+
elif osr.id == 'ubuntu':
|
56
|
+
return UbuntuPlatform()
|
57
|
+
|
58
|
+
else:
|
59
|
+
return GenericLinuxPlatform()
|
60
|
+
|
61
|
+
elif plat == 'darwin':
|
62
|
+
return DarwinPlatform()
|
63
|
+
|
64
|
+
else:
|
65
|
+
return UnknownPlatform()
|
66
|
+
|
67
|
+
|
68
|
+
@cached_nullary
|
69
|
+
def detect_system_platform() -> Platform:
|
70
|
+
platform = _detect_system_platform()
|
71
|
+
log.info('Detected platform: %r', platform)
|
72
|
+
return platform
|
File without changes
|