ominfra 0.0.0.dev182__py3-none-any.whl → 0.0.0.dev184__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/configs.py +33 -0
- ominfra/manage/deploy/apps.py +1 -1
- ominfra/manage/deploy/conf/__init__.py +0 -0
- ominfra/manage/deploy/conf/inject.py +17 -0
- ominfra/manage/deploy/{conf.py → conf/manager.py} +28 -6
- ominfra/manage/deploy/conf/specs.py +95 -0
- ominfra/manage/deploy/inject.py +9 -18
- ominfra/manage/deploy/inject_.py +13 -0
- ominfra/manage/deploy/paths/specs.py +10 -0
- ominfra/manage/deploy/specs.py +1 -59
- ominfra/manage/deploy/tags.py +2 -3
- ominfra/scripts/journald2aws.py +42 -0
- ominfra/scripts/manage.py +291 -177
- ominfra/scripts/supervisor.py +42 -0
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/RECORD +20 -16
- ominfra/systemd.py +0 -18
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev182.dist-info → ominfra-0.0.0.dev184.dist-info}/top_level.txt +0 -0
ominfra/configs.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
# @omlish-lite
|
3
|
+
import io
|
3
4
|
import json
|
4
5
|
import os.path
|
5
6
|
import typing as ta
|
@@ -14,6 +15,11 @@ T = ta.TypeVar('T')
|
|
14
15
|
|
15
16
|
ConfigMapping = ta.Mapping[str, ta.Any]
|
16
17
|
|
18
|
+
IniConfigSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
19
|
+
|
20
|
+
|
21
|
+
##
|
22
|
+
|
17
23
|
|
18
24
|
def parse_config_file(
|
19
25
|
name: str,
|
@@ -58,6 +64,9 @@ def read_config_file(
|
|
58
64
|
return msh.unmarshal_obj(config_dct, cls)
|
59
65
|
|
60
66
|
|
67
|
+
##
|
68
|
+
|
69
|
+
|
61
70
|
def build_config_named_children(
|
62
71
|
o: ta.Union[
|
63
72
|
ta.Sequence[ConfigMapping],
|
@@ -94,3 +103,27 @@ def build_config_named_children(
|
|
94
103
|
seen.add(n)
|
95
104
|
|
96
105
|
return lst
|
106
|
+
|
107
|
+
|
108
|
+
##
|
109
|
+
|
110
|
+
|
111
|
+
def render_ini_config(
|
112
|
+
settings_by_section: IniConfigSectionSettingsMap,
|
113
|
+
) -> str:
|
114
|
+
out = io.StringIO()
|
115
|
+
|
116
|
+
for i, (section, settings) in enumerate(settings_by_section.items()):
|
117
|
+
if i:
|
118
|
+
out.write('\n')
|
119
|
+
|
120
|
+
out.write(f'[{section}]\n')
|
121
|
+
|
122
|
+
for k, v in settings.items():
|
123
|
+
if isinstance(v, str):
|
124
|
+
out.write(f'{k}={v}\n')
|
125
|
+
else:
|
126
|
+
for vv in v:
|
127
|
+
out.write(f'{k}={vv}\n')
|
128
|
+
|
129
|
+
return out.getvalue()
|
ominfra/manage/deploy/apps.py
CHANGED
@@ -6,7 +6,7 @@ from omlish.lite.cached import cached_nullary
|
|
6
6
|
from omlish.lite.check import check
|
7
7
|
from omlish.os.paths import relative_symlink
|
8
8
|
|
9
|
-
from .conf import DeployConfManager
|
9
|
+
from .conf.manager import DeployConfManager
|
10
10
|
from .git import DeployGitManager
|
11
11
|
from .paths.owners import DeployPathOwner
|
12
12
|
from .paths.paths import DeployPath
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
5
|
+
from omlish.lite.inject import InjectorBindings
|
6
|
+
from omlish.lite.inject import inj
|
7
|
+
|
8
|
+
from ..inject_ import bind_deploy_manager
|
9
|
+
from .manager import DeployConfManager
|
10
|
+
|
11
|
+
|
12
|
+
def bind_deploy_conf() -> InjectorBindings:
|
13
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
14
|
+
bind_deploy_manager(DeployConfManager),
|
15
|
+
]
|
16
|
+
|
17
|
+
return inj.as_bindings(*lst)
|
@@ -20,20 +20,40 @@ import os.path
|
|
20
20
|
import typing as ta
|
21
21
|
|
22
22
|
from omlish.lite.check import check
|
23
|
+
from omlish.lite.json import json_dumps_pretty
|
24
|
+
from omlish.lite.strings import strip_with_newline
|
23
25
|
from omlish.os.paths import is_path_in_dir
|
24
26
|
from omlish.os.paths import relative_symlink
|
25
27
|
|
26
|
-
from
|
28
|
+
from ....configs import render_ini_config
|
29
|
+
from ..paths.paths import DeployPath
|
30
|
+
from ..tags import DEPLOY_TAG_SEPARATOR
|
31
|
+
from ..tags import DeployApp
|
32
|
+
from ..tags import DeployConf
|
33
|
+
from ..tags import DeployTagMap
|
34
|
+
from .specs import DeployAppConfContent
|
27
35
|
from .specs import DeployAppConfFile
|
28
36
|
from .specs import DeployAppConfLink
|
29
37
|
from .specs import DeployAppConfSpec
|
30
|
-
from .
|
31
|
-
from .
|
32
|
-
from .
|
33
|
-
from .tags import DeployTagMap
|
38
|
+
from .specs import IniDeployAppConfContent
|
39
|
+
from .specs import JsonDeployAppConfContent
|
40
|
+
from .specs import RawDeployAppConfContent
|
34
41
|
|
35
42
|
|
36
43
|
class DeployConfManager:
|
44
|
+
def _render_app_conf_content(self, ac: DeployAppConfContent) -> str:
|
45
|
+
if isinstance(ac, RawDeployAppConfContent):
|
46
|
+
return ac.body
|
47
|
+
|
48
|
+
elif isinstance(ac, JsonDeployAppConfContent):
|
49
|
+
return strip_with_newline(json_dumps_pretty(ac.obj))
|
50
|
+
|
51
|
+
elif isinstance(ac, IniDeployAppConfContent):
|
52
|
+
return strip_with_newline(render_ini_config(ac.sections))
|
53
|
+
|
54
|
+
else:
|
55
|
+
raise TypeError(ac)
|
56
|
+
|
37
57
|
async def _write_app_conf_file(
|
38
58
|
self,
|
39
59
|
acf: DeployAppConfFile,
|
@@ -42,10 +62,12 @@ class DeployConfManager:
|
|
42
62
|
conf_file = os.path.join(app_conf_dir, acf.path)
|
43
63
|
check.arg(is_path_in_dir(app_conf_dir, conf_file))
|
44
64
|
|
65
|
+
body = self._render_app_conf_content(acf.content)
|
66
|
+
|
45
67
|
os.makedirs(os.path.dirname(conf_file), exist_ok=True)
|
46
68
|
|
47
69
|
with open(conf_file, 'w') as f: # noqa
|
48
|
-
f.write(
|
70
|
+
f.write(body)
|
49
71
|
|
50
72
|
#
|
51
73
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
3
|
+
import dataclasses as dc
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.check import check
|
7
|
+
from omlish.lite.marshal import register_single_field_type_obj_marshaler
|
8
|
+
|
9
|
+
from ....configs import IniConfigSectionSettingsMap
|
10
|
+
from ..paths.specs import check_valid_deploy_spec_path
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
|
15
|
+
|
16
|
+
class DeployAppConfContent(abc.ABC): # noqa
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
|
22
|
+
|
23
|
+
@register_single_field_type_obj_marshaler('body')
|
24
|
+
@dc.dataclass(frozen=True)
|
25
|
+
class RawDeployAppConfContent(DeployAppConfContent):
|
26
|
+
body: str
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
|
31
|
+
|
32
|
+
@register_single_field_type_obj_marshaler('obj')
|
33
|
+
@dc.dataclass(frozen=True)
|
34
|
+
class JsonDeployAppConfContent(DeployAppConfContent):
|
35
|
+
obj: ta.Any
|
36
|
+
|
37
|
+
|
38
|
+
#
|
39
|
+
|
40
|
+
|
41
|
+
@register_single_field_type_obj_marshaler('sections')
|
42
|
+
@dc.dataclass(frozen=True)
|
43
|
+
class IniDeployAppConfContent(DeployAppConfContent):
|
44
|
+
sections: IniConfigSectionSettingsMap
|
45
|
+
|
46
|
+
|
47
|
+
##
|
48
|
+
|
49
|
+
|
50
|
+
@dc.dataclass(frozen=True)
|
51
|
+
class DeployAppConfFile:
|
52
|
+
path: str
|
53
|
+
content: DeployAppConfContent
|
54
|
+
|
55
|
+
def __post_init__(self) -> None:
|
56
|
+
check_valid_deploy_spec_path(self.path)
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
|
61
|
+
|
62
|
+
@dc.dataclass(frozen=True)
|
63
|
+
class DeployAppConfLink: # noqa
|
64
|
+
"""
|
65
|
+
May be either:
|
66
|
+
- @conf(.ext)* - links a single file in root of app conf dir to conf/@conf/@dst(.ext)*
|
67
|
+
- @conf/file - links a single file in a single subdir to conf/@conf/@dst--file
|
68
|
+
- @conf/ - links a directory in root of app conf dir to conf/@conf/@dst/
|
69
|
+
"""
|
70
|
+
|
71
|
+
src: str
|
72
|
+
|
73
|
+
kind: ta.Literal['current_only', 'all_active'] = 'current_only'
|
74
|
+
|
75
|
+
def __post_init__(self) -> None:
|
76
|
+
check_valid_deploy_spec_path(self.src)
|
77
|
+
if '/' in self.src:
|
78
|
+
check.equal(self.src.count('/'), 1)
|
79
|
+
|
80
|
+
|
81
|
+
##
|
82
|
+
|
83
|
+
|
84
|
+
@dc.dataclass(frozen=True)
|
85
|
+
class DeployAppConfSpec:
|
86
|
+
files: ta.Optional[ta.Sequence[DeployAppConfFile]] = None
|
87
|
+
|
88
|
+
links: ta.Optional[ta.Sequence[DeployAppConfLink]] = None
|
89
|
+
|
90
|
+
def __post_init__(self) -> None:
|
91
|
+
if self.files:
|
92
|
+
seen: ta.Set[str] = set()
|
93
|
+
for f in self.files:
|
94
|
+
check.not_in(f.path, seen)
|
95
|
+
seen.add(f.path)
|
ominfra/manage/deploy/inject.py
CHANGED
@@ -14,16 +14,16 @@ from ..commands.inject import bind_command
|
|
14
14
|
from .apps import DeployAppManager
|
15
15
|
from .commands import DeployCommand
|
16
16
|
from .commands import DeployCommandExecutor
|
17
|
-
from .conf import
|
17
|
+
from .conf.inject import bind_deploy_conf
|
18
18
|
from .config import DeployConfig
|
19
19
|
from .deploy import DeployManager
|
20
20
|
from .driver import DeployDriver
|
21
21
|
from .driver import DeployDriverFactory
|
22
22
|
from .git import DeployGitManager
|
23
|
+
from .inject_ import bind_deploy_manager
|
23
24
|
from .interp import InterpCommand
|
24
25
|
from .interp import InterpCommandExecutor
|
25
26
|
from .paths.inject import bind_deploy_paths
|
26
|
-
from .paths.owners import DeployPathOwner
|
27
27
|
from .specs import DeploySpec
|
28
28
|
from .tags import DeployTime
|
29
29
|
from .tmp import DeployHomeAtomics
|
@@ -90,6 +90,8 @@ def bind_deploy(
|
|
90
90
|
lst: ta.List[InjectorBindingOrBindings] = [
|
91
91
|
inj.bind(deploy_config),
|
92
92
|
|
93
|
+
bind_deploy_conf(),
|
94
|
+
|
93
95
|
bind_deploy_paths(),
|
94
96
|
|
95
97
|
bind_deploy_scope(),
|
@@ -97,27 +99,16 @@ def bind_deploy(
|
|
97
99
|
|
98
100
|
#
|
99
101
|
|
100
|
-
def bind_manager(cls: type) -> InjectorBindings:
|
101
|
-
return inj.as_bindings(
|
102
|
-
inj.bind(cls, singleton=True),
|
103
|
-
|
104
|
-
*([inj.bind(DeployPathOwner, to_key=cls, array=True)] if issubclass(cls, DeployPathOwner) else []),
|
105
|
-
)
|
106
|
-
|
107
|
-
#
|
108
|
-
|
109
102
|
lst.extend([
|
110
|
-
|
111
|
-
|
112
|
-
bind_manager(DeployConfManager),
|
103
|
+
bind_deploy_manager(DeployAppManager),
|
113
104
|
|
114
|
-
|
105
|
+
bind_deploy_manager(DeployGitManager),
|
115
106
|
|
116
|
-
|
107
|
+
bind_deploy_manager(DeployManager),
|
117
108
|
|
118
|
-
|
109
|
+
bind_deploy_manager(DeployTmpManager),
|
119
110
|
|
120
|
-
|
111
|
+
bind_deploy_manager(DeployVenvManager),
|
121
112
|
])
|
122
113
|
|
123
114
|
#
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
from omlish.lite.inject import InjectorBindings
|
3
|
+
from omlish.lite.inject import inj
|
4
|
+
|
5
|
+
from .paths.owners import DeployPathOwner
|
6
|
+
|
7
|
+
|
8
|
+
def bind_deploy_manager(cls: type) -> InjectorBindings:
|
9
|
+
return inj.as_bindings(
|
10
|
+
inj.bind(cls, singleton=True),
|
11
|
+
|
12
|
+
*([inj.bind(DeployPathOwner, to_key=cls, array=True)] if issubclass(cls, DeployPathOwner) else []),
|
13
|
+
)
|
ominfra/manage/deploy/specs.py
CHANGED
@@ -7,6 +7,7 @@ import typing as ta
|
|
7
7
|
from omlish.lite.cached import cached_nullary
|
8
8
|
from omlish.lite.check import check
|
9
9
|
|
10
|
+
from .conf.specs import DeployAppConfSpec
|
10
11
|
from .tags import DeployApp
|
11
12
|
from .tags import DeployAppKey
|
12
13
|
from .tags import DeployKey
|
@@ -21,14 +22,6 @@ KeyDeployTagT = ta.TypeVar('KeyDeployTagT', bound='KeyDeployTag')
|
|
21
22
|
##
|
22
23
|
|
23
24
|
|
24
|
-
def check_valid_deploy_spec_path(s: str) -> str:
|
25
|
-
check.non_empty_str(s)
|
26
|
-
for c in ['..', '//']:
|
27
|
-
check.not_in(c, s)
|
28
|
-
check.arg(not s.startswith('/'))
|
29
|
-
return s
|
30
|
-
|
31
|
-
|
32
25
|
class DeploySpecKeyed(ta.Generic[KeyDeployTagT]):
|
33
26
|
@cached_nullary
|
34
27
|
def _key_str(self) -> str:
|
@@ -83,57 +76,6 @@ class DeployVenvSpec:
|
|
83
76
|
##
|
84
77
|
|
85
78
|
|
86
|
-
@dc.dataclass(frozen=True)
|
87
|
-
class DeployAppConfFile:
|
88
|
-
path: str
|
89
|
-
body: str
|
90
|
-
|
91
|
-
def __post_init__(self) -> None:
|
92
|
-
check_valid_deploy_spec_path(self.path)
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
@dc.dataclass(frozen=True)
|
99
|
-
class DeployAppConfLink: # noqa
|
100
|
-
"""
|
101
|
-
May be either:
|
102
|
-
- @conf(.ext)* - links a single file in root of app conf dir to conf/@conf/@dst(.ext)*
|
103
|
-
- @conf/file - links a single file in a single subdir to conf/@conf/@dst--file
|
104
|
-
- @conf/ - links a directory in root of app conf dir to conf/@conf/@dst/
|
105
|
-
"""
|
106
|
-
|
107
|
-
src: str
|
108
|
-
|
109
|
-
kind: ta.Literal['current_only', 'all_active'] = 'current_only'
|
110
|
-
|
111
|
-
def __post_init__(self) -> None:
|
112
|
-
check_valid_deploy_spec_path(self.src)
|
113
|
-
if '/' in self.src:
|
114
|
-
check.equal(self.src.count('/'), 1)
|
115
|
-
|
116
|
-
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
@dc.dataclass(frozen=True)
|
121
|
-
class DeployAppConfSpec:
|
122
|
-
files: ta.Optional[ta.Sequence[DeployAppConfFile]] = None
|
123
|
-
|
124
|
-
links: ta.Optional[ta.Sequence[DeployAppConfLink]] = None
|
125
|
-
|
126
|
-
def __post_init__(self) -> None:
|
127
|
-
if self.files:
|
128
|
-
seen: ta.Set[str] = set()
|
129
|
-
for f in self.files:
|
130
|
-
check.not_in(f.path, seen)
|
131
|
-
seen.add(f.path)
|
132
|
-
|
133
|
-
|
134
|
-
##
|
135
|
-
|
136
|
-
|
137
79
|
@dc.dataclass(frozen=True)
|
138
80
|
class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
|
139
81
|
app: DeployApp
|
ominfra/manage/deploy/tags.py
CHANGED
@@ -4,8 +4,7 @@ import dataclasses as dc
|
|
4
4
|
import typing as ta
|
5
5
|
|
6
6
|
from omlish.lite.check import check
|
7
|
-
from omlish.lite.marshal import
|
8
|
-
from omlish.lite.marshal import register_type_obj_marshaler
|
7
|
+
from omlish.lite.marshal import register_single_field_type_obj_marshaler
|
9
8
|
|
10
9
|
|
11
10
|
##
|
@@ -84,7 +83,7 @@ def _register_deploy_tag(cls):
|
|
84
83
|
_DEPLOY_TAGS_BY_NAME[cls.tag_name] = cls
|
85
84
|
_DEPLOY_TAGS_BY_KWARG[cls.tag_kwarg] = cls
|
86
85
|
|
87
|
-
|
86
|
+
register_single_field_type_obj_marshaler('s', cls)
|
88
87
|
|
89
88
|
return cls
|
90
89
|
|
ominfra/scripts/journald2aws.py
CHANGED
@@ -74,6 +74,7 @@ ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
|
|
74
74
|
|
75
75
|
# ../../../configs.py
|
76
76
|
ConfigMapping = ta.Mapping[str, ta.Any]
|
77
|
+
IniConfigSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
77
78
|
|
78
79
|
# ../../../threadworkers.py
|
79
80
|
ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
|
@@ -2804,6 +2805,17 @@ def register_type_obj_marshaler(ty: type, om: ObjMarshaler) -> None:
|
|
2804
2805
|
_REGISTERED_OBJ_MARSHALERS_BY_TYPE[ty] = om
|
2805
2806
|
|
2806
2807
|
|
2808
|
+
def register_single_field_type_obj_marshaler(fld, ty=None):
|
2809
|
+
def inner(ty): # noqa
|
2810
|
+
register_type_obj_marshaler(ty, SingleFieldObjMarshaler(ty, fld))
|
2811
|
+
return ty
|
2812
|
+
|
2813
|
+
if ty is not None:
|
2814
|
+
return inner(ty)
|
2815
|
+
else:
|
2816
|
+
return inner
|
2817
|
+
|
2818
|
+
|
2807
2819
|
##
|
2808
2820
|
|
2809
2821
|
|
@@ -3261,6 +3273,9 @@ class AwsLogMessageBuilder:
|
|
3261
3273
|
# ../../../../configs.py
|
3262
3274
|
|
3263
3275
|
|
3276
|
+
##
|
3277
|
+
|
3278
|
+
|
3264
3279
|
def parse_config_file(
|
3265
3280
|
name: str,
|
3266
3281
|
f: ta.TextIO,
|
@@ -3304,6 +3319,9 @@ def read_config_file(
|
|
3304
3319
|
return msh.unmarshal_obj(config_dct, cls)
|
3305
3320
|
|
3306
3321
|
|
3322
|
+
##
|
3323
|
+
|
3324
|
+
|
3307
3325
|
def build_config_named_children(
|
3308
3326
|
o: ta.Union[
|
3309
3327
|
ta.Sequence[ConfigMapping],
|
@@ -3342,6 +3360,30 @@ def build_config_named_children(
|
|
3342
3360
|
return lst
|
3343
3361
|
|
3344
3362
|
|
3363
|
+
##
|
3364
|
+
|
3365
|
+
|
3366
|
+
def render_ini_config(
|
3367
|
+
settings_by_section: IniConfigSectionSettingsMap,
|
3368
|
+
) -> str:
|
3369
|
+
out = io.StringIO()
|
3370
|
+
|
3371
|
+
for i, (section, settings) in enumerate(settings_by_section.items()):
|
3372
|
+
if i:
|
3373
|
+
out.write('\n')
|
3374
|
+
|
3375
|
+
out.write(f'[{section}]\n')
|
3376
|
+
|
3377
|
+
for k, v in settings.items():
|
3378
|
+
if isinstance(v, str):
|
3379
|
+
out.write(f'{k}={v}\n')
|
3380
|
+
else:
|
3381
|
+
for vv in v:
|
3382
|
+
out.write(f'{k}={vv}\n')
|
3383
|
+
|
3384
|
+
return out.getvalue()
|
3385
|
+
|
3386
|
+
|
3345
3387
|
########################################
|
3346
3388
|
# ../../../../journald/messages.py
|
3347
3389
|
|
ominfra/scripts/manage.py
CHANGED
@@ -129,6 +129,7 @@ AtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
|
|
129
129
|
|
130
130
|
# ../configs.py
|
131
131
|
ConfigMapping = ta.Mapping[str, ta.Any]
|
132
|
+
IniConfigSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
132
133
|
|
133
134
|
# ../../omlish/subprocesses.py
|
134
135
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
@@ -4252,6 +4253,18 @@ def build_command_name_map(crs: CommandRegistrations) -> CommandNameMap:
|
|
4252
4253
|
return CommandNameMap(dct)
|
4253
4254
|
|
4254
4255
|
|
4256
|
+
########################################
|
4257
|
+
# ../deploy/paths/specs.py
|
4258
|
+
|
4259
|
+
|
4260
|
+
def check_valid_deploy_spec_path(s: str) -> str:
|
4261
|
+
check.non_empty_str(s)
|
4262
|
+
for c in ['..', '//']:
|
4263
|
+
check.not_in(c, s)
|
4264
|
+
check.arg(not s.startswith('/'))
|
4265
|
+
return s
|
4266
|
+
|
4267
|
+
|
4255
4268
|
########################################
|
4256
4269
|
# ../remote/config.py
|
4257
4270
|
|
@@ -6225,6 +6238,17 @@ def register_type_obj_marshaler(ty: type, om: ObjMarshaler) -> None:
|
|
6225
6238
|
_REGISTERED_OBJ_MARSHALERS_BY_TYPE[ty] = om
|
6226
6239
|
|
6227
6240
|
|
6241
|
+
def register_single_field_type_obj_marshaler(fld, ty=None):
|
6242
|
+
def inner(ty): # noqa
|
6243
|
+
register_type_obj_marshaler(ty, SingleFieldObjMarshaler(ty, fld))
|
6244
|
+
return ty
|
6245
|
+
|
6246
|
+
if ty is not None:
|
6247
|
+
return inner(ty)
|
6248
|
+
else:
|
6249
|
+
return inner
|
6250
|
+
|
6251
|
+
|
6228
6252
|
##
|
6229
6253
|
|
6230
6254
|
|
@@ -6821,6 +6845,9 @@ def bind_interp_uv() -> InjectorBindings:
|
|
6821
6845
|
# ../../configs.py
|
6822
6846
|
|
6823
6847
|
|
6848
|
+
##
|
6849
|
+
|
6850
|
+
|
6824
6851
|
def parse_config_file(
|
6825
6852
|
name: str,
|
6826
6853
|
f: ta.TextIO,
|
@@ -6864,6 +6891,9 @@ def read_config_file(
|
|
6864
6891
|
return msh.unmarshal_obj(config_dct, cls)
|
6865
6892
|
|
6866
6893
|
|
6894
|
+
##
|
6895
|
+
|
6896
|
+
|
6867
6897
|
def build_config_named_children(
|
6868
6898
|
o: ta.Union[
|
6869
6899
|
ta.Sequence[ConfigMapping],
|
@@ -6902,6 +6932,30 @@ def build_config_named_children(
|
|
6902
6932
|
return lst
|
6903
6933
|
|
6904
6934
|
|
6935
|
+
##
|
6936
|
+
|
6937
|
+
|
6938
|
+
def render_ini_config(
|
6939
|
+
settings_by_section: IniConfigSectionSettingsMap,
|
6940
|
+
) -> str:
|
6941
|
+
out = io.StringIO()
|
6942
|
+
|
6943
|
+
for i, (section, settings) in enumerate(settings_by_section.items()):
|
6944
|
+
if i:
|
6945
|
+
out.write('\n')
|
6946
|
+
|
6947
|
+
out.write(f'[{section}]\n')
|
6948
|
+
|
6949
|
+
for k, v in settings.items():
|
6950
|
+
if isinstance(v, str):
|
6951
|
+
out.write(f'{k}={v}\n')
|
6952
|
+
else:
|
6953
|
+
for vv in v:
|
6954
|
+
out.write(f'{k}={vv}\n')
|
6955
|
+
|
6956
|
+
return out.getvalue()
|
6957
|
+
|
6958
|
+
|
6905
6959
|
########################################
|
6906
6960
|
# ../commands/marshal.py
|
6907
6961
|
|
@@ -7035,7 +7089,7 @@ def _register_deploy_tag(cls):
|
|
7035
7089
|
_DEPLOY_TAGS_BY_NAME[cls.tag_name] = cls
|
7036
7090
|
_DEPLOY_TAGS_BY_KWARG[cls.tag_kwarg] = cls
|
7037
7091
|
|
7038
|
-
|
7092
|
+
register_single_field_type_obj_marshaler('s', cls)
|
7039
7093
|
|
7040
7094
|
return cls
|
7041
7095
|
|
@@ -7808,6 +7862,95 @@ class LocalCommandExecutor(CommandExecutor):
|
|
7808
7862
|
return await ce.execute(cmd)
|
7809
7863
|
|
7810
7864
|
|
7865
|
+
########################################
|
7866
|
+
# ../deploy/conf/specs.py
|
7867
|
+
|
7868
|
+
|
7869
|
+
##
|
7870
|
+
|
7871
|
+
|
7872
|
+
class DeployAppConfContent(abc.ABC): # noqa
|
7873
|
+
pass
|
7874
|
+
|
7875
|
+
|
7876
|
+
#
|
7877
|
+
|
7878
|
+
|
7879
|
+
@register_single_field_type_obj_marshaler('body')
|
7880
|
+
@dc.dataclass(frozen=True)
|
7881
|
+
class RawDeployAppConfContent(DeployAppConfContent):
|
7882
|
+
body: str
|
7883
|
+
|
7884
|
+
|
7885
|
+
#
|
7886
|
+
|
7887
|
+
|
7888
|
+
@register_single_field_type_obj_marshaler('obj')
|
7889
|
+
@dc.dataclass(frozen=True)
|
7890
|
+
class JsonDeployAppConfContent(DeployAppConfContent):
|
7891
|
+
obj: ta.Any
|
7892
|
+
|
7893
|
+
|
7894
|
+
#
|
7895
|
+
|
7896
|
+
|
7897
|
+
@register_single_field_type_obj_marshaler('sections')
|
7898
|
+
@dc.dataclass(frozen=True)
|
7899
|
+
class IniDeployAppConfContent(DeployAppConfContent):
|
7900
|
+
sections: IniConfigSectionSettingsMap
|
7901
|
+
|
7902
|
+
|
7903
|
+
##
|
7904
|
+
|
7905
|
+
|
7906
|
+
@dc.dataclass(frozen=True)
|
7907
|
+
class DeployAppConfFile:
|
7908
|
+
path: str
|
7909
|
+
content: DeployAppConfContent
|
7910
|
+
|
7911
|
+
def __post_init__(self) -> None:
|
7912
|
+
check_valid_deploy_spec_path(self.path)
|
7913
|
+
|
7914
|
+
|
7915
|
+
##
|
7916
|
+
|
7917
|
+
|
7918
|
+
@dc.dataclass(frozen=True)
|
7919
|
+
class DeployAppConfLink: # noqa
|
7920
|
+
"""
|
7921
|
+
May be either:
|
7922
|
+
- @conf(.ext)* - links a single file in root of app conf dir to conf/@conf/@dst(.ext)*
|
7923
|
+
- @conf/file - links a single file in a single subdir to conf/@conf/@dst--file
|
7924
|
+
- @conf/ - links a directory in root of app conf dir to conf/@conf/@dst/
|
7925
|
+
"""
|
7926
|
+
|
7927
|
+
src: str
|
7928
|
+
|
7929
|
+
kind: ta.Literal['current_only', 'all_active'] = 'current_only'
|
7930
|
+
|
7931
|
+
def __post_init__(self) -> None:
|
7932
|
+
check_valid_deploy_spec_path(self.src)
|
7933
|
+
if '/' in self.src:
|
7934
|
+
check.equal(self.src.count('/'), 1)
|
7935
|
+
|
7936
|
+
|
7937
|
+
##
|
7938
|
+
|
7939
|
+
|
7940
|
+
@dc.dataclass(frozen=True)
|
7941
|
+
class DeployAppConfSpec:
|
7942
|
+
files: ta.Optional[ta.Sequence[DeployAppConfFile]] = None
|
7943
|
+
|
7944
|
+
links: ta.Optional[ta.Sequence[DeployAppConfLink]] = None
|
7945
|
+
|
7946
|
+
def __post_init__(self) -> None:
|
7947
|
+
if self.files:
|
7948
|
+
seen: ta.Set[str] = set()
|
7949
|
+
for f in self.files:
|
7950
|
+
check.not_in(f.path, seen)
|
7951
|
+
seen.add(f.path)
|
7952
|
+
|
7953
|
+
|
7811
7954
|
########################################
|
7812
7955
|
# ../deploy/deploy.py
|
7813
7956
|
|
@@ -8037,164 +8180,6 @@ class DeployPath:
|
|
8037
8180
|
return cls(tuple(DeployPathPart.parse(p) for p in ps))
|
8038
8181
|
|
8039
8182
|
|
8040
|
-
########################################
|
8041
|
-
# ../deploy/specs.py
|
8042
|
-
|
8043
|
-
|
8044
|
-
##
|
8045
|
-
|
8046
|
-
|
8047
|
-
def check_valid_deploy_spec_path(s: str) -> str:
|
8048
|
-
check.non_empty_str(s)
|
8049
|
-
for c in ['..', '//']:
|
8050
|
-
check.not_in(c, s)
|
8051
|
-
check.arg(not s.startswith('/'))
|
8052
|
-
return s
|
8053
|
-
|
8054
|
-
|
8055
|
-
class DeploySpecKeyed(ta.Generic[KeyDeployTagT]):
|
8056
|
-
@cached_nullary
|
8057
|
-
def _key_str(self) -> str:
|
8058
|
-
return hashlib.sha256(repr(self).encode('utf-8')).hexdigest()[:8]
|
8059
|
-
|
8060
|
-
@abc.abstractmethod
|
8061
|
-
def key(self) -> KeyDeployTagT:
|
8062
|
-
raise NotImplementedError
|
8063
|
-
|
8064
|
-
|
8065
|
-
##
|
8066
|
-
|
8067
|
-
|
8068
|
-
@dc.dataclass(frozen=True)
|
8069
|
-
class DeployGitRepo:
|
8070
|
-
host: ta.Optional[str] = None
|
8071
|
-
username: ta.Optional[str] = None
|
8072
|
-
path: ta.Optional[str] = None
|
8073
|
-
|
8074
|
-
def __post_init__(self) -> None:
|
8075
|
-
check.not_in('..', check.non_empty_str(self.host))
|
8076
|
-
check.not_in('.', check.non_empty_str(self.path))
|
8077
|
-
|
8078
|
-
|
8079
|
-
@dc.dataclass(frozen=True)
|
8080
|
-
class DeployGitSpec:
|
8081
|
-
repo: DeployGitRepo
|
8082
|
-
rev: DeployRev
|
8083
|
-
|
8084
|
-
subtrees: ta.Optional[ta.Sequence[str]] = None
|
8085
|
-
|
8086
|
-
def __post_init__(self) -> None:
|
8087
|
-
check.non_empty_str(self.rev)
|
8088
|
-
if self.subtrees is not None:
|
8089
|
-
for st in self.subtrees:
|
8090
|
-
check.non_empty_str(st)
|
8091
|
-
|
8092
|
-
|
8093
|
-
##
|
8094
|
-
|
8095
|
-
|
8096
|
-
@dc.dataclass(frozen=True)
|
8097
|
-
class DeployVenvSpec:
|
8098
|
-
interp: ta.Optional[str] = None
|
8099
|
-
|
8100
|
-
requirements_files: ta.Optional[ta.Sequence[str]] = None
|
8101
|
-
extra_dependencies: ta.Optional[ta.Sequence[str]] = None
|
8102
|
-
|
8103
|
-
use_uv: bool = False
|
8104
|
-
|
8105
|
-
|
8106
|
-
##
|
8107
|
-
|
8108
|
-
|
8109
|
-
@dc.dataclass(frozen=True)
|
8110
|
-
class DeployAppConfFile:
|
8111
|
-
path: str
|
8112
|
-
body: str
|
8113
|
-
|
8114
|
-
def __post_init__(self) -> None:
|
8115
|
-
check_valid_deploy_spec_path(self.path)
|
8116
|
-
|
8117
|
-
|
8118
|
-
#
|
8119
|
-
|
8120
|
-
|
8121
|
-
@dc.dataclass(frozen=True)
|
8122
|
-
class DeployAppConfLink: # noqa
|
8123
|
-
"""
|
8124
|
-
May be either:
|
8125
|
-
- @conf(.ext)* - links a single file in root of app conf dir to conf/@conf/@dst(.ext)*
|
8126
|
-
- @conf/file - links a single file in a single subdir to conf/@conf/@dst--file
|
8127
|
-
- @conf/ - links a directory in root of app conf dir to conf/@conf/@dst/
|
8128
|
-
"""
|
8129
|
-
|
8130
|
-
src: str
|
8131
|
-
|
8132
|
-
kind: ta.Literal['current_only', 'all_active'] = 'current_only'
|
8133
|
-
|
8134
|
-
def __post_init__(self) -> None:
|
8135
|
-
check_valid_deploy_spec_path(self.src)
|
8136
|
-
if '/' in self.src:
|
8137
|
-
check.equal(self.src.count('/'), 1)
|
8138
|
-
|
8139
|
-
|
8140
|
-
#
|
8141
|
-
|
8142
|
-
|
8143
|
-
@dc.dataclass(frozen=True)
|
8144
|
-
class DeployAppConfSpec:
|
8145
|
-
files: ta.Optional[ta.Sequence[DeployAppConfFile]] = None
|
8146
|
-
|
8147
|
-
links: ta.Optional[ta.Sequence[DeployAppConfLink]] = None
|
8148
|
-
|
8149
|
-
def __post_init__(self) -> None:
|
8150
|
-
if self.files:
|
8151
|
-
seen: ta.Set[str] = set()
|
8152
|
-
for f in self.files:
|
8153
|
-
check.not_in(f.path, seen)
|
8154
|
-
seen.add(f.path)
|
8155
|
-
|
8156
|
-
|
8157
|
-
##
|
8158
|
-
|
8159
|
-
|
8160
|
-
@dc.dataclass(frozen=True)
|
8161
|
-
class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
|
8162
|
-
app: DeployApp
|
8163
|
-
|
8164
|
-
git: DeployGitSpec
|
8165
|
-
|
8166
|
-
venv: ta.Optional[DeployVenvSpec] = None
|
8167
|
-
|
8168
|
-
conf: ta.Optional[DeployAppConfSpec] = None
|
8169
|
-
|
8170
|
-
# @ta.override
|
8171
|
-
def key(self) -> DeployAppKey:
|
8172
|
-
return DeployAppKey(self._key_str())
|
8173
|
-
|
8174
|
-
|
8175
|
-
##
|
8176
|
-
|
8177
|
-
|
8178
|
-
@dc.dataclass(frozen=True)
|
8179
|
-
class DeploySpec(DeploySpecKeyed[DeployKey]):
|
8180
|
-
home: DeployHome
|
8181
|
-
|
8182
|
-
apps: ta.Sequence[DeployAppSpec]
|
8183
|
-
|
8184
|
-
def __post_init__(self) -> None:
|
8185
|
-
check.non_empty_str(self.home)
|
8186
|
-
|
8187
|
-
seen: ta.Set[DeployApp] = set()
|
8188
|
-
for a in self.apps:
|
8189
|
-
if a.app in seen:
|
8190
|
-
raise KeyError(a.app)
|
8191
|
-
seen.add(a.app)
|
8192
|
-
|
8193
|
-
# @ta.override
|
8194
|
-
def key(self) -> DeployKey:
|
8195
|
-
return DeployKey(self._key_str())
|
8196
|
-
|
8197
|
-
|
8198
8183
|
########################################
|
8199
8184
|
# ../remote/execution.py
|
8200
8185
|
"""
|
@@ -9155,7 +9140,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
|
|
9155
9140
|
|
9156
9141
|
|
9157
9142
|
########################################
|
9158
|
-
# ../deploy/conf.py
|
9143
|
+
# ../deploy/conf/manager.py
|
9159
9144
|
"""
|
9160
9145
|
TODO:
|
9161
9146
|
- @conf DeployPathPlaceholder? :|
|
@@ -9176,6 +9161,19 @@ TODO:
|
|
9176
9161
|
|
9177
9162
|
|
9178
9163
|
class DeployConfManager:
|
9164
|
+
def _render_app_conf_content(self, ac: DeployAppConfContent) -> str:
|
9165
|
+
if isinstance(ac, RawDeployAppConfContent):
|
9166
|
+
return ac.body
|
9167
|
+
|
9168
|
+
elif isinstance(ac, JsonDeployAppConfContent):
|
9169
|
+
return strip_with_newline(json_dumps_pretty(ac.obj))
|
9170
|
+
|
9171
|
+
elif isinstance(ac, IniDeployAppConfContent):
|
9172
|
+
return strip_with_newline(render_ini_config(ac.sections))
|
9173
|
+
|
9174
|
+
else:
|
9175
|
+
raise TypeError(ac)
|
9176
|
+
|
9179
9177
|
async def _write_app_conf_file(
|
9180
9178
|
self,
|
9181
9179
|
acf: DeployAppConfFile,
|
@@ -9184,10 +9182,12 @@ class DeployConfManager:
|
|
9184
9182
|
conf_file = os.path.join(app_conf_dir, acf.path)
|
9185
9183
|
check.arg(is_path_in_dir(app_conf_dir, conf_file))
|
9186
9184
|
|
9185
|
+
body = self._render_app_conf_content(acf.content)
|
9186
|
+
|
9187
9187
|
os.makedirs(os.path.dirname(conf_file), exist_ok=True)
|
9188
9188
|
|
9189
9189
|
with open(conf_file, 'w') as f: # noqa
|
9190
|
-
f.write(
|
9190
|
+
f.write(body)
|
9191
9191
|
|
9192
9192
|
#
|
9193
9193
|
|
@@ -9363,6 +9363,105 @@ class SingleDirDeployPathOwner(DeployPathOwner, abc.ABC):
|
|
9363
9363
|
return self._owned_deploy_paths
|
9364
9364
|
|
9365
9365
|
|
9366
|
+
########################################
|
9367
|
+
# ../deploy/specs.py
|
9368
|
+
|
9369
|
+
|
9370
|
+
##
|
9371
|
+
|
9372
|
+
|
9373
|
+
class DeploySpecKeyed(ta.Generic[KeyDeployTagT]):
|
9374
|
+
@cached_nullary
|
9375
|
+
def _key_str(self) -> str:
|
9376
|
+
return hashlib.sha256(repr(self).encode('utf-8')).hexdigest()[:8]
|
9377
|
+
|
9378
|
+
@abc.abstractmethod
|
9379
|
+
def key(self) -> KeyDeployTagT:
|
9380
|
+
raise NotImplementedError
|
9381
|
+
|
9382
|
+
|
9383
|
+
##
|
9384
|
+
|
9385
|
+
|
9386
|
+
@dc.dataclass(frozen=True)
|
9387
|
+
class DeployGitRepo:
|
9388
|
+
host: ta.Optional[str] = None
|
9389
|
+
username: ta.Optional[str] = None
|
9390
|
+
path: ta.Optional[str] = None
|
9391
|
+
|
9392
|
+
def __post_init__(self) -> None:
|
9393
|
+
check.not_in('..', check.non_empty_str(self.host))
|
9394
|
+
check.not_in('.', check.non_empty_str(self.path))
|
9395
|
+
|
9396
|
+
|
9397
|
+
@dc.dataclass(frozen=True)
|
9398
|
+
class DeployGitSpec:
|
9399
|
+
repo: DeployGitRepo
|
9400
|
+
rev: DeployRev
|
9401
|
+
|
9402
|
+
subtrees: ta.Optional[ta.Sequence[str]] = None
|
9403
|
+
|
9404
|
+
def __post_init__(self) -> None:
|
9405
|
+
check.non_empty_str(self.rev)
|
9406
|
+
if self.subtrees is not None:
|
9407
|
+
for st in self.subtrees:
|
9408
|
+
check.non_empty_str(st)
|
9409
|
+
|
9410
|
+
|
9411
|
+
##
|
9412
|
+
|
9413
|
+
|
9414
|
+
@dc.dataclass(frozen=True)
|
9415
|
+
class DeployVenvSpec:
|
9416
|
+
interp: ta.Optional[str] = None
|
9417
|
+
|
9418
|
+
requirements_files: ta.Optional[ta.Sequence[str]] = None
|
9419
|
+
extra_dependencies: ta.Optional[ta.Sequence[str]] = None
|
9420
|
+
|
9421
|
+
use_uv: bool = False
|
9422
|
+
|
9423
|
+
|
9424
|
+
##
|
9425
|
+
|
9426
|
+
|
9427
|
+
@dc.dataclass(frozen=True)
|
9428
|
+
class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
|
9429
|
+
app: DeployApp
|
9430
|
+
|
9431
|
+
git: DeployGitSpec
|
9432
|
+
|
9433
|
+
venv: ta.Optional[DeployVenvSpec] = None
|
9434
|
+
|
9435
|
+
conf: ta.Optional[DeployAppConfSpec] = None
|
9436
|
+
|
9437
|
+
# @ta.override
|
9438
|
+
def key(self) -> DeployAppKey:
|
9439
|
+
return DeployAppKey(self._key_str())
|
9440
|
+
|
9441
|
+
|
9442
|
+
##
|
9443
|
+
|
9444
|
+
|
9445
|
+
@dc.dataclass(frozen=True)
|
9446
|
+
class DeploySpec(DeploySpecKeyed[DeployKey]):
|
9447
|
+
home: DeployHome
|
9448
|
+
|
9449
|
+
apps: ta.Sequence[DeployAppSpec]
|
9450
|
+
|
9451
|
+
def __post_init__(self) -> None:
|
9452
|
+
check.non_empty_str(self.home)
|
9453
|
+
|
9454
|
+
seen: ta.Set[DeployApp] = set()
|
9455
|
+
for a in self.apps:
|
9456
|
+
if a.app in seen:
|
9457
|
+
raise KeyError(a.app)
|
9458
|
+
seen.add(a.app)
|
9459
|
+
|
9460
|
+
# @ta.override
|
9461
|
+
def key(self) -> DeployKey:
|
9462
|
+
return DeployKey(self._key_str())
|
9463
|
+
|
9464
|
+
|
9366
9465
|
########################################
|
9367
9466
|
# ../remote/_main.py
|
9368
9467
|
|
@@ -10222,6 +10321,18 @@ def bind_commands(
|
|
10222
10321
|
return inj.as_bindings(*lst)
|
10223
10322
|
|
10224
10323
|
|
10324
|
+
########################################
|
10325
|
+
# ../deploy/inject_.py
|
10326
|
+
|
10327
|
+
|
10328
|
+
def bind_deploy_manager(cls: type) -> InjectorBindings:
|
10329
|
+
return inj.as_bindings(
|
10330
|
+
inj.bind(cls, singleton=True),
|
10331
|
+
|
10332
|
+
*([inj.bind(DeployPathOwner, to_key=cls, array=True)] if issubclass(cls, DeployPathOwner) else []),
|
10333
|
+
)
|
10334
|
+
|
10335
|
+
|
10225
10336
|
########################################
|
10226
10337
|
# ../deploy/paths/manager.py
|
10227
10338
|
|
@@ -10579,6 +10690,18 @@ class PyenvInterpProvider(InterpProvider):
|
|
10579
10690
|
return Interp(exe, version)
|
10580
10691
|
|
10581
10692
|
|
10693
|
+
########################################
|
10694
|
+
# ../deploy/conf/inject.py
|
10695
|
+
|
10696
|
+
|
10697
|
+
def bind_deploy_conf() -> InjectorBindings:
|
10698
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10699
|
+
bind_deploy_manager(DeployConfManager),
|
10700
|
+
]
|
10701
|
+
|
10702
|
+
return inj.as_bindings(*lst)
|
10703
|
+
|
10704
|
+
|
10582
10705
|
########################################
|
10583
10706
|
# ../deploy/git.py
|
10584
10707
|
"""
|
@@ -11424,6 +11547,8 @@ def bind_deploy(
|
|
11424
11547
|
lst: ta.List[InjectorBindingOrBindings] = [
|
11425
11548
|
inj.bind(deploy_config),
|
11426
11549
|
|
11550
|
+
bind_deploy_conf(),
|
11551
|
+
|
11427
11552
|
bind_deploy_paths(),
|
11428
11553
|
|
11429
11554
|
bind_deploy_scope(),
|
@@ -11431,27 +11556,16 @@ def bind_deploy(
|
|
11431
11556
|
|
11432
11557
|
#
|
11433
11558
|
|
11434
|
-
def bind_manager(cls: type) -> InjectorBindings:
|
11435
|
-
return inj.as_bindings(
|
11436
|
-
inj.bind(cls, singleton=True),
|
11437
|
-
|
11438
|
-
*([inj.bind(DeployPathOwner, to_key=cls, array=True)] if issubclass(cls, DeployPathOwner) else []),
|
11439
|
-
)
|
11440
|
-
|
11441
|
-
#
|
11442
|
-
|
11443
11559
|
lst.extend([
|
11444
|
-
|
11445
|
-
|
11446
|
-
bind_manager(DeployConfManager),
|
11560
|
+
bind_deploy_manager(DeployAppManager),
|
11447
11561
|
|
11448
|
-
|
11562
|
+
bind_deploy_manager(DeployGitManager),
|
11449
11563
|
|
11450
|
-
|
11564
|
+
bind_deploy_manager(DeployManager),
|
11451
11565
|
|
11452
|
-
|
11566
|
+
bind_deploy_manager(DeployTmpManager),
|
11453
11567
|
|
11454
|
-
|
11568
|
+
bind_deploy_manager(DeployVenvManager),
|
11455
11569
|
])
|
11456
11570
|
|
11457
11571
|
#
|
ominfra/scripts/supervisor.py
CHANGED
@@ -143,6 +143,7 @@ SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'S
|
|
143
143
|
|
144
144
|
# ../configs.py
|
145
145
|
ConfigMapping = ta.Mapping[str, ta.Any]
|
146
|
+
IniConfigSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
146
147
|
|
147
148
|
# ../../omlish/http/handlers.py
|
148
149
|
HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse'] # ta.TypeAlias
|
@@ -5371,6 +5372,17 @@ def register_type_obj_marshaler(ty: type, om: ObjMarshaler) -> None:
|
|
5371
5372
|
_REGISTERED_OBJ_MARSHALERS_BY_TYPE[ty] = om
|
5372
5373
|
|
5373
5374
|
|
5375
|
+
def register_single_field_type_obj_marshaler(fld, ty=None):
|
5376
|
+
def inner(ty): # noqa
|
5377
|
+
register_type_obj_marshaler(ty, SingleFieldObjMarshaler(ty, fld))
|
5378
|
+
return ty
|
5379
|
+
|
5380
|
+
if ty is not None:
|
5381
|
+
return inner(ty)
|
5382
|
+
else:
|
5383
|
+
return inner
|
5384
|
+
|
5385
|
+
|
5374
5386
|
##
|
5375
5387
|
|
5376
5388
|
|
@@ -5839,6 +5851,9 @@ class SocketHandler(abc.ABC):
|
|
5839
5851
|
# ../../configs.py
|
5840
5852
|
|
5841
5853
|
|
5854
|
+
##
|
5855
|
+
|
5856
|
+
|
5842
5857
|
def parse_config_file(
|
5843
5858
|
name: str,
|
5844
5859
|
f: ta.TextIO,
|
@@ -5882,6 +5897,9 @@ def read_config_file(
|
|
5882
5897
|
return msh.unmarshal_obj(config_dct, cls)
|
5883
5898
|
|
5884
5899
|
|
5900
|
+
##
|
5901
|
+
|
5902
|
+
|
5885
5903
|
def build_config_named_children(
|
5886
5904
|
o: ta.Union[
|
5887
5905
|
ta.Sequence[ConfigMapping],
|
@@ -5920,6 +5938,30 @@ def build_config_named_children(
|
|
5920
5938
|
return lst
|
5921
5939
|
|
5922
5940
|
|
5941
|
+
##
|
5942
|
+
|
5943
|
+
|
5944
|
+
def render_ini_config(
|
5945
|
+
settings_by_section: IniConfigSectionSettingsMap,
|
5946
|
+
) -> str:
|
5947
|
+
out = io.StringIO()
|
5948
|
+
|
5949
|
+
for i, (section, settings) in enumerate(settings_by_section.items()):
|
5950
|
+
if i:
|
5951
|
+
out.write('\n')
|
5952
|
+
|
5953
|
+
out.write(f'[{section}]\n')
|
5954
|
+
|
5955
|
+
for k, v in settings.items():
|
5956
|
+
if isinstance(v, str):
|
5957
|
+
out.write(f'{k}={v}\n')
|
5958
|
+
else:
|
5959
|
+
for vv in v:
|
5960
|
+
out.write(f'{k}={vv}\n')
|
5961
|
+
|
5962
|
+
return out.getvalue()
|
5963
|
+
|
5964
|
+
|
5923
5965
|
########################################
|
5924
5966
|
# ../pipes.py
|
5925
5967
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev184
|
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.
|
16
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omdev==0.0.0.dev184
|
16
|
+
Requires-Dist: omlish==0.0.0.dev184
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -2,10 +2,9 @@ ominfra/.manifests.json,sha256=8KREXxMAlsilZOktXPYru1ND3V5hFI22vnrp6hT3bio,589
|
|
2
2
|
ominfra/__about__.py,sha256=6i1AoruFYQCd-PyhhbDQDWY2d1tiQu9nkwWr-fXAqfY,705
|
3
3
|
ominfra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
ominfra/cmds.py,sha256=E0AfnvEmnKntXWvmLW5L05_NeDpBET1VBXn7vV6EwBQ,2083
|
5
|
-
ominfra/configs.py,sha256=
|
5
|
+
ominfra/configs.py,sha256=UrwZrzsnU4E305OoFH_eAcyI8e82LQZ2yhy8WnuAUGM,3055
|
6
6
|
ominfra/pyremote.py,sha256=HLfAZl3Xw5CpxLS5PS380zqCyE7n3vKVksIYT2Fbdc8,15197
|
7
7
|
ominfra/ssh.py,sha256=jQpc4WvkMckIfk4vILda8zFaeharRqc_6wxW50b0OjQ,5431
|
8
|
-
ominfra/systemd.py,sha256=sepFytuiRjoWHJbiFH8Ti9zm1gvWBaUXNyvSRiVLi-k,419
|
9
8
|
ominfra/threadworkers.py,sha256=oX4ubZn7h932saXpRIJu2MNhBExgGGMuGhdXarZxLJw,4948
|
10
9
|
ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
10
|
ominfra/clouds/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -45,25 +44,30 @@ ominfra/manage/commands/ping.py,sha256=DVZFzL1Z_f-Bq53vxMrL3xOi0iK_nMonJE4KvQf9w
|
|
45
44
|
ominfra/manage/commands/subprocess.py,sha256=yHGMbAI-xKe_9BUs5IZ3Yav8qRE-I9aGnBtTwW15Pnw,2440
|
46
45
|
ominfra/manage/commands/types.py,sha256=XFZPeqeIBAaIIQF3pdPbGxLlb-LCrz6WtlDWO2q_vz0,210
|
47
46
|
ominfra/manage/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
|
-
ominfra/manage/deploy/apps.py,sha256=
|
47
|
+
ominfra/manage/deploy/apps.py,sha256=d0OwAVqLyr-_lrsmaeTH69G4b6vIm6ESvmWqKjA-Xn0,4750
|
49
48
|
ominfra/manage/deploy/commands.py,sha256=U74HYQ4nhvH7znAKyXGOmZfdnll2gMWxKWVW4GzxG-0,830
|
50
|
-
ominfra/manage/deploy/conf.py,sha256=fNfFlIb-bB3KAzaYZcjrbqaqKSiSq0Lpk0mIF6WgXiw,5410
|
51
49
|
ominfra/manage/deploy/config.py,sha256=kPpl8TRisz295cM4oj-RHA6oh5jdcJ_N9pVpkl_doO8,114
|
52
50
|
ominfra/manage/deploy/deploy.py,sha256=vyBTbBm51HhRE-MQNvxEt39F8uOYsB4ToqZ3zmVkpqU,819
|
53
51
|
ominfra/manage/deploy/driver.py,sha256=kSriXFC8L_EpOcHFGxNZDBGyxV_fZAAF95y-czisnwE,1352
|
54
52
|
ominfra/manage/deploy/git.py,sha256=g4wzUuSu9HwWSDhdVX-7BvA2htMwtWbRcHaoDy-xOJ4,3960
|
55
|
-
ominfra/manage/deploy/inject.py,sha256=
|
53
|
+
ominfra/manage/deploy/inject.py,sha256=8Y1wUEnWCFh9a7YEzHi1GaPfK18c6wP6eVVkKKheScw,3378
|
54
|
+
ominfra/manage/deploy/inject_.py,sha256=LR7gEkVx2ldUoQZsGvIcm1Y4QXCVDnLIAdc3LHhQiD4,392
|
56
55
|
ominfra/manage/deploy/interp.py,sha256=_5fuHrY5ZA0eGbnNcOqAhAMSWI1UNvbm0l29eDjE5fI,1037
|
57
|
-
ominfra/manage/deploy/specs.py,sha256
|
58
|
-
ominfra/manage/deploy/tags.py,sha256=
|
56
|
+
ominfra/manage/deploy/specs.py,sha256=-WSVpRwiwgXVUh4HVdFUYxadxbLz1WX1ARmQXvmbLlw,2445
|
57
|
+
ominfra/manage/deploy/tags.py,sha256=3BU0OtHQJ1Vk9B_U7Q3Cq1rbVgxcXrFki24WU0nPX1M,5106
|
59
58
|
ominfra/manage/deploy/tmp.py,sha256=FqXoVpIpVe8-KWNu7kXt37A4jKdK_y7h_YFvtrUoOG8,729
|
60
59
|
ominfra/manage/deploy/types.py,sha256=ZcIoheZ3zW7n0IZiqTRW_Uo3JyWWeWg5nyKGryvGc2I,112
|
61
60
|
ominfra/manage/deploy/venvs.py,sha256=1Ic3yKap9bTduqHorz1MpmSiQPh9x-vxhLLxgpVpRdc,1592
|
61
|
+
ominfra/manage/deploy/conf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
62
|
+
ominfra/manage/deploy/conf/inject.py,sha256=xHZQr7oaJCxaKgpJ0H-hgiQNGt4QsskhT3f5v7xrFwE,451
|
63
|
+
ominfra/manage/deploy/conf/manager.py,sha256=29txtcAeRNUqK2MD1V5Q-82EoeExdkkV4fRvPnc8GTs,6226
|
64
|
+
ominfra/manage/deploy/conf/specs.py,sha256=r9Tf6i0TPVOTuoS__F5Yz1v14Btfqtb1nvUdgEaNeBU,2030
|
62
65
|
ominfra/manage/deploy/paths/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
66
|
ominfra/manage/deploy/paths/inject.py,sha256=X81C-Qhef1LQ7tILWvkomBwFTvgooLVmWRnKL7TeVoI,596
|
64
67
|
ominfra/manage/deploy/paths/manager.py,sha256=Dnl8euyZQYDGwDzkMvgPAwOssseducr5kP6T0qzVXQk,929
|
65
68
|
ominfra/manage/deploy/paths/owners.py,sha256=sgCdKOFve8XZOtoTjrFrOrJd_MhZOGXo4yFJAFGRQ_s,1229
|
66
69
|
ominfra/manage/deploy/paths/paths.py,sha256=i7g8YdYOh4M_jgJXtafTbFkRhlu469cfGxAJAuB3fVY,5531
|
70
|
+
ominfra/manage/deploy/paths/specs.py,sha256=0cXJI7xjevv4qco3qn4jAs9i5pGyupJ3CFAyJh8y1z0,244
|
67
71
|
ominfra/manage/deploy/paths/types.py,sha256=TGgtSASmdyuZ2maZnvahfA0QxPLWlHBtpDeIEoEDGxk,112
|
68
72
|
ominfra/manage/remote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
73
|
ominfra/manage/remote/_main.py,sha256=p5KoiS2WMw6QAqlDl_Zun-JybmCsy8awIfpBMLBjGMY,4356
|
@@ -87,9 +91,9 @@ ominfra/manage/targets/connection.py,sha256=rVI1YJxFClcF-sdttqWyIz9_XjPI01GUdwxY
|
|
87
91
|
ominfra/manage/targets/inject.py,sha256=P4597xWM-V3I_gCt2O71OLhYQkkXtuJvkYRsIbhhMcE,1561
|
88
92
|
ominfra/manage/targets/targets.py,sha256=7GP6UAZyJFEhpkJN6UQdpr_WN3p7C76v-s445y-WB6U,1885
|
89
93
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
|
-
ominfra/scripts/journald2aws.py,sha256
|
91
|
-
ominfra/scripts/manage.py,sha256=
|
92
|
-
ominfra/scripts/supervisor.py,sha256=
|
94
|
+
ominfra/scripts/journald2aws.py,sha256=-XlQ9s2yKZpOQqTQhvEb44q-cYX317mobkjlyCyfUro,158588
|
95
|
+
ominfra/scripts/manage.py,sha256=ZH8YdqXxnFdcGb6uCcXotg2wbke0MnniRquPwy3aAPg,330216
|
96
|
+
ominfra/scripts/supervisor.py,sha256=WpK_AR5LwmvxLfCyjylMV4_Ud2iNZ6k9QBUxiseSmqY,282876
|
93
97
|
ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
|
94
98
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
95
99
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
@@ -131,9 +135,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
|
131
135
|
ominfra/tailscale/cli.py,sha256=3FnJbgpLw6gInTfhERd1mDy9ijjMUGxkdYVo43Tnxx4,3555
|
132
136
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
133
137
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
134
|
-
ominfra-0.0.0.
|
135
|
-
ominfra-0.0.0.
|
136
|
-
ominfra-0.0.0.
|
137
|
-
ominfra-0.0.0.
|
138
|
-
ominfra-0.0.0.
|
139
|
-
ominfra-0.0.0.
|
138
|
+
ominfra-0.0.0.dev184.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
139
|
+
ominfra-0.0.0.dev184.dist-info/METADATA,sha256=_2qh8ot4_hmhmocdB0x3-yeQWQ8jzM5fpedBUm9rFrs,731
|
140
|
+
ominfra-0.0.0.dev184.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
141
|
+
ominfra-0.0.0.dev184.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
142
|
+
ominfra-0.0.0.dev184.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
143
|
+
ominfra-0.0.0.dev184.dist-info/RECORD,,
|
ominfra/systemd.py
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# @omlish-lite
|
2
|
-
import io
|
3
|
-
import typing as ta
|
4
|
-
|
5
|
-
|
6
|
-
def render_systemd_unit(settings_by_section: ta.Mapping[str, ta.Mapping[str, str]]) -> str:
|
7
|
-
out = io.StringIO()
|
8
|
-
|
9
|
-
for i, (section, settings) in enumerate(settings_by_section.items()):
|
10
|
-
if i:
|
11
|
-
out.write('\n')
|
12
|
-
|
13
|
-
out.write(f'[{section}]\n')
|
14
|
-
|
15
|
-
for k, v in settings.items():
|
16
|
-
out.write(f'{k}={v}\n')
|
17
|
-
|
18
|
-
return out.getvalue()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|