ominfra 0.0.0.dev191__py3-none-any.whl → 0.0.0.dev193__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
ominfra/configs.py CHANGED
@@ -1,11 +1,10 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  # @omlish-lite
3
- import io
4
3
  import json
5
4
  import os.path
6
5
  import typing as ta
7
6
 
8
- from omdev.toml.parser import toml_loads
7
+ from omlish.formats.toml.parser import toml_loads
9
8
  from omlish.lite.check import check
10
9
  from omlish.lite.marshal import OBJ_MARSHALER_MANAGER
11
10
  from omlish.lite.marshal import ObjMarshalerManager
@@ -15,8 +14,6 @@ T = ta.TypeVar('T')
15
14
 
16
15
  ConfigMapping = ta.Mapping[str, ta.Any]
17
16
 
18
- IniConfigSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
19
-
20
17
 
21
18
  ##
22
19
 
@@ -103,27 +100,3 @@ def build_config_named_children(
103
100
  seen.add(n)
104
101
 
105
102
  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()
@@ -84,6 +84,8 @@ class DeployAppManager(DeployPathOwner):
84
84
  spec: DeployAppSpec,
85
85
  home: DeployHome,
86
86
  tags: DeployTagMap,
87
+ *,
88
+ conf_string_ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
87
89
  ) -> PreparedApp:
88
90
  spec_json = json_dumps_pretty(self._msh.marshal_obj(spec))
89
91
 
@@ -140,9 +142,17 @@ class DeployAppManager(DeployPathOwner):
140
142
  if spec.conf is not None:
141
143
  conf_dir = os.path.join(app_dir, 'conf')
142
144
  rkw.update(conf_dir=conf_dir)
145
+
146
+ conf_ns: ta.Dict[str, ta.Any] = dict(
147
+ **(conf_string_ns or {}),
148
+ app=spec.app.s,
149
+ app_dir=app_dir.rstrip('/'),
150
+ )
151
+
143
152
  await self._conf.write_app_conf(
144
153
  spec.conf,
145
154
  conf_dir,
155
+ string_ns=conf_ns,
146
156
  )
147
157
 
148
158
  #
@@ -29,7 +29,7 @@ from omlish.os.paths import relative_symlink
29
29
  from omserv.nginx.configs import NginxConfigItems
30
30
  from omserv.nginx.configs import render_nginx_config_str
31
31
 
32
- from ....configs import render_ini_config
32
+ from omlish.formats.ini.sections import render_ini_sections
33
33
  from ..paths.paths import DeployPath
34
34
  from ..tags import DEPLOY_TAG_SEPARATOR
35
35
  from ..tags import DeployApp
@@ -100,7 +100,7 @@ class DeployConfManager:
100
100
 
101
101
  elif isinstance(ac, IniDeployAppConfContent):
102
102
  ini_sections = pcc(ac.sections)
103
- return strip_with_newline(render_ini_config(ini_sections))
103
+ return strip_with_newline(render_ini_sections(ini_sections))
104
104
 
105
105
  elif isinstance(ac, NginxDeployAppConfContent):
106
106
  nginx_items = NginxConfigItems.of(pcc(ac.items))
@@ -133,9 +133,15 @@ class DeployConfManager:
133
133
  self,
134
134
  spec: DeployAppConfSpec,
135
135
  app_conf_dir: str,
136
+ *,
137
+ string_ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
136
138
  ) -> None:
137
- def process_str(s: str) -> str:
138
- return s
139
+ process_str: ta.Any
140
+ if string_ns is not None:
141
+ def process_str(s: str) -> str:
142
+ return s.format(**string_ns)
143
+ else:
144
+ process_str = None
139
145
 
140
146
  for acf in spec.files or []:
141
147
  await self._write_app_conf_file(
@@ -6,7 +6,7 @@ import typing as ta
6
6
  from omlish.lite.check import check
7
7
  from omlish.lite.marshal import register_single_field_type_obj_marshaler
8
8
 
9
- from ....configs import IniConfigSectionSettingsMap
9
+ from omlish.formats.ini.sections import IniSectionSettingsMap
10
10
  from ..paths.specs import check_valid_deploy_spec_path
11
11
 
12
12
 
@@ -41,7 +41,7 @@ class JsonDeployAppConfContent(DeployAppConfContent):
41
41
  @register_single_field_type_obj_marshaler('sections')
42
42
  @dc.dataclass(frozen=True)
43
43
  class IniDeployAppConfContent(DeployAppConfContent):
44
- sections: IniConfigSectionSettingsMap
44
+ sections: IniSectionSettingsMap
45
45
 
46
46
 
47
47
  #
@@ -30,7 +30,7 @@ from .types import DeployHome
30
30
  ##
31
31
 
32
32
 
33
- DEPLOY_TAG_DATETIME_FMT = '%Y%m%dT%H%M%SZ'
33
+ DEPLOY_TAG_DATETIME_FMT = '%Y-%m-%d-T-%H-%M-%S-%f-Z'
34
34
 
35
35
 
36
36
  DeployManagerUtcClock = ta.NewType('DeployManagerUtcClock', Func0[datetime.datetime])
@@ -183,8 +183,9 @@ class DeployDriver:
183
183
 
184
184
  das: ta.Set[DeployApp] = {a.app for a in self._spec.apps}
185
185
  las: ta.Set[DeployApp] = set(self._spec.app_links.apps)
186
- if (ras := das & las):
187
- raise RuntimeError(f'Must not specify apps as both deploy and link: {sorted(a.s for a in ras)}')
186
+ ras: ta.Set[DeployApp] = set(self._spec.app_links.removed_apps)
187
+ check.empty(das & (las | ras))
188
+ check.empty(las & ras)
188
189
 
189
190
  #
190
191
 
@@ -230,10 +231,10 @@ class DeployDriver:
230
231
  cad = abs_real_path(os.path.join(current_link, 'apps'))
231
232
  if os.path.exists(cad):
232
233
  for d in os.listdir(cad):
233
- if (da := DeployApp(d)) not in das:
234
+ if (da := DeployApp(d)) not in das and da not in ras:
234
235
  las.add(da)
235
236
 
236
- for la in self._spec.app_links.apps:
237
+ for la in las:
237
238
  await self._drive_app_link(
238
239
  la,
239
240
  current_link,
@@ -263,10 +264,16 @@ class DeployDriver:
263
264
  #
264
265
 
265
266
  async def _drive_app_deploy(self, app: DeployAppSpec) -> None:
267
+ current_deploy_link = os.path.join(self._home, self._deploys.CURRENT_DEPLOY_LINK.render())
268
+
266
269
  pa = await self._apps.prepare_app(
267
270
  app,
268
271
  self._home,
269
272
  self.tags,
273
+ conf_string_ns=dict(
274
+ deploy_home=self._home,
275
+ current_deploy_link=current_deploy_link,
276
+ ),
270
277
  )
271
278
 
272
279
  #
@@ -91,7 +91,9 @@ class DeployGitManager(SingleDirDeployPathOwner):
91
91
 
92
92
  async def fetch(self, rev: DeployRev) -> None:
93
93
  await self.init()
94
- await self._call('git', 'fetch', '--depth=1', 'origin', rev)
94
+
95
+ # This fetch shouldn't be depth=1 - git doesn't reuse local data with shallow fetches.
96
+ await self._call('git', 'fetch', 'origin', rev)
95
97
 
96
98
  #
97
99
 
@@ -95,6 +95,8 @@ class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
95
95
  class DeployAppLinksSpec:
96
96
  apps: ta.Sequence[DeployApp] = ()
97
97
 
98
+ removed_apps: ta.Sequence[DeployApp] = ()
99
+
98
100
  exclude_unspecified: bool = False
99
101
 
100
102
 
@@ -8,6 +8,7 @@ TODO:
8
8
  - ominfra.systemd / x.sd_orphans
9
9
  """
10
10
  import os.path
11
+ import shutil
11
12
  import sys
12
13
  import typing as ta
13
14
 
@@ -101,7 +102,7 @@ class DeploySystemdManager:
101
102
 
102
103
  #
103
104
 
104
- if sys.platform == 'linux':
105
+ if sys.platform == 'linux' and shutil.which('systemctl') is not None:
105
106
  async def reload() -> None:
106
107
  await asyncio_subprocesses.check_call('systemctl', '--user', 'daemon-reload')
107
108
 
@@ -52,7 +52,7 @@ if sys.version_info < (3, 8):
52
52
  ########################################
53
53
 
54
54
 
55
- # ../../../../omdev/toml/parser.py
55
+ # ../../../../omlish/formats/toml/parser.py
56
56
  TomlParseFloat = ta.Callable[[str], ta.Any]
57
57
  TomlKey = ta.Tuple[str, ...]
58
58
  TomlPos = int # ta.TypeAlias
@@ -74,7 +74,6 @@ 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
78
77
 
79
78
  # ../../../threadworkers.py
80
79
  ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
@@ -84,7 +83,7 @@ SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlia
84
83
 
85
84
 
86
85
  ########################################
87
- # ../../../../../omdev/toml/parser.py
86
+ # ../../../../../omlish/formats/toml/parser.py
88
87
  # SPDX-License-Identifier: MIT
89
88
  # SPDX-FileCopyrightText: 2021 Taneli Hukkinen
90
89
  # Licensed to PSF under a Contributor Agreement.
@@ -3371,30 +3370,6 @@ def build_config_named_children(
3371
3370
  return lst
3372
3371
 
3373
3372
 
3374
- ##
3375
-
3376
-
3377
- def render_ini_config(
3378
- settings_by_section: IniConfigSectionSettingsMap,
3379
- ) -> str:
3380
- out = io.StringIO()
3381
-
3382
- for i, (section, settings) in enumerate(settings_by_section.items()):
3383
- if i:
3384
- out.write('\n')
3385
-
3386
- out.write(f'[{section}]\n')
3387
-
3388
- for k, v in settings.items():
3389
- if isinstance(v, str):
3390
- out.write(f'{k}={v}\n')
3391
- else:
3392
- for vv in v:
3393
- out.write(f'{k}={vv}\n')
3394
-
3395
- return out.getvalue()
3396
-
3397
-
3398
3373
  ########################################
3399
3374
  # ../../../../journald/messages.py
3400
3375