ominfra 0.0.0.dev182__py3-none-any.whl → 0.0.0.dev184__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|