dsw-tdk 4.12.0__py2.py3-none-any.whl → 4.14.0__py2.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.
- dsw/tdk/__main__.py +1 -0
- dsw/tdk/api_client.py +58 -30
- dsw/tdk/build_info.py +4 -4
- dsw/tdk/cli.py +59 -44
- dsw/tdk/consts.py +5 -4
- dsw/tdk/core.py +128 -99
- dsw/tdk/model.py +77 -67
- dsw/tdk/templates/starter.j2 +1 -2
- dsw/tdk/utils.py +8 -9
- dsw/tdk/validation.py +72 -18
- {dsw_tdk-4.12.0.dist-info → dsw_tdk-4.14.0.dist-info}/METADATA +3 -3
- dsw_tdk-4.14.0.dist-info/RECORD +20 -0
- {dsw_tdk-4.12.0.dist-info → dsw_tdk-4.14.0.dist-info}/WHEEL +1 -1
- dsw_tdk-4.12.0.dist-info/RECORD +0 -20
- {dsw_tdk-4.12.0.dist-info → dsw_tdk-4.14.0.dist-info}/LICENSE +0 -0
- {dsw_tdk-4.12.0.dist-info → dsw_tdk-4.14.0.dist-info}/entry_points.txt +0 -0
- {dsw_tdk-4.12.0.dist-info → dsw_tdk-4.14.0.dist-info}/top_level.txt +0 -0
dsw/tdk/core.py
CHANGED
|
@@ -7,11 +7,9 @@ import pathlib
|
|
|
7
7
|
import re
|
|
8
8
|
import shutil
|
|
9
9
|
import tempfile
|
|
10
|
-
import watchfiles # type: ignore
|
|
11
10
|
import zipfile
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
from typing import List, Optional, Tuple
|
|
12
|
+
import watchfiles
|
|
15
13
|
|
|
16
14
|
from .api_client import DSWAPIClient, DSWCommunicationError
|
|
17
15
|
from .consts import DEFAULT_ENCODING, REGEX_SEMVER
|
|
@@ -20,7 +18,7 @@ from .utils import UUIDGen, create_dot_env
|
|
|
20
18
|
from .validation import ValidationError, TemplateValidator
|
|
21
19
|
|
|
22
20
|
|
|
23
|
-
ChangeItem =
|
|
21
|
+
ChangeItem = tuple[watchfiles.Change, pathlib.Path]
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
def _change(item: ChangeItem, root: pathlib.Path) -> str:
|
|
@@ -50,9 +48,11 @@ METAMODEL_VERSION_SUPPORT = {
|
|
|
50
48
|
13: (4, 3, 0),
|
|
51
49
|
14: (4, 10, 0),
|
|
52
50
|
15: (4, 12, 0),
|
|
51
|
+
16: (4, 13, 0),
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
|
|
55
|
+
# pylint: disable=too-many-public-methods
|
|
56
56
|
class TDKCore:
|
|
57
57
|
|
|
58
58
|
def _check_metamodel_version(self):
|
|
@@ -63,24 +63,24 @@ class TDKCore:
|
|
|
63
63
|
if 'v' == api_version[0]:
|
|
64
64
|
api_version = api_version[1:]
|
|
65
65
|
if not re.match(REGEX_SEMVER, api_version):
|
|
66
|
-
self.logger.warning(
|
|
66
|
+
self.logger.warning('Using non-stable release of API: %s', self.remote_version)
|
|
67
67
|
return
|
|
68
68
|
parts = api_version.split('.')
|
|
69
69
|
ver = (int(parts[0]), int(parts[1]), int(parts[2]))
|
|
70
70
|
vtag = f'v{ver[0]}.{ver[1]}.{ver[2]}'
|
|
71
71
|
hint = 'Fix your metamodelVersion in template.json and/or visit docs'
|
|
72
|
-
if mm_ver not in METAMODEL_VERSION_SUPPORT
|
|
72
|
+
if mm_ver not in METAMODEL_VERSION_SUPPORT:
|
|
73
73
|
raise TDKProcessingError(f'Unknown metamodel version: {mm_ver}', hint)
|
|
74
74
|
min_version = METAMODEL_VERSION_SUPPORT[mm_ver]
|
|
75
75
|
if min_version > ver:
|
|
76
76
|
raise TDKProcessingError(f'Unsupported metamodel version for API {vtag}', hint)
|
|
77
|
-
if mm_ver + 1 in METAMODEL_VERSION_SUPPORT
|
|
77
|
+
if mm_ver + 1 in METAMODEL_VERSION_SUPPORT:
|
|
78
78
|
max_version = METAMODEL_VERSION_SUPPORT[mm_ver + 1]
|
|
79
79
|
if ver >= max_version:
|
|
80
80
|
raise TDKProcessingError(f'Unsupported metamodel version for API {vtag}', hint)
|
|
81
81
|
|
|
82
|
-
def __init__(self, template:
|
|
83
|
-
client:
|
|
82
|
+
def __init__(self, template: Template | None = None, project: TemplateProject | None = None,
|
|
83
|
+
client: DSWAPIClient | None = None, logger: logging.Logger | None = None):
|
|
84
84
|
self.template = template
|
|
85
85
|
self.project = project
|
|
86
86
|
self.client = client
|
|
@@ -112,13 +112,13 @@ class TDKCore:
|
|
|
112
112
|
return self.client
|
|
113
113
|
|
|
114
114
|
async def init_client(self, api_url: str, api_key: str):
|
|
115
|
-
self.logger.info(
|
|
115
|
+
self.logger.info('Connecting to %s', api_url)
|
|
116
116
|
self.client = DSWAPIClient(api_url=api_url, api_key=api_key)
|
|
117
117
|
self.remote_version = await self.client.get_api_version()
|
|
118
118
|
user = await self.client.get_current_user()
|
|
119
|
-
self.logger.info(
|
|
120
|
-
|
|
121
|
-
self.logger.debug(
|
|
119
|
+
self.logger.info('Successfully authenticated as %s %s (%s)',
|
|
120
|
+
user['firstName'], user['lastName'], user['email'])
|
|
121
|
+
self.logger.debug('Connected to API version %s', self.remote_version)
|
|
122
122
|
|
|
123
123
|
def prepare_local(self, template_dir):
|
|
124
124
|
self.logger.debug('Preparing local template project')
|
|
@@ -130,32 +130,32 @@ class TDKCore:
|
|
|
130
130
|
self.safe_project.load()
|
|
131
131
|
|
|
132
132
|
async def load_remote(self, template_id: str):
|
|
133
|
-
self.logger.info(
|
|
133
|
+
self.logger.info('Retrieving template draft %s', template_id)
|
|
134
134
|
self.template = await self.safe_client.get_template_draft(remote_id=template_id)
|
|
135
135
|
self.logger.debug('Retrieving template draft files')
|
|
136
136
|
files = await self.safe_client.get_template_draft_files(remote_id=template_id)
|
|
137
|
-
self.logger.info(
|
|
137
|
+
self.logger.info('Retrieved %s file(s)', len(files))
|
|
138
138
|
for tfile in files:
|
|
139
139
|
self.safe_template.files[tfile.filename.as_posix()] = tfile
|
|
140
140
|
self.logger.debug('Retrieving template draft assets')
|
|
141
141
|
assets = await self.safe_client.get_template_draft_assets(remote_id=template_id)
|
|
142
|
-
self.logger.info(
|
|
142
|
+
self.logger.info('Retrieved %s asset(s)', len(assets))
|
|
143
143
|
for tfile in assets:
|
|
144
144
|
self.safe_template.files[tfile.filename.as_posix()] = tfile
|
|
145
145
|
|
|
146
146
|
async def download_bundle(self, template_id: str) -> bytes:
|
|
147
|
-
self.logger.info(
|
|
147
|
+
self.logger.info('Retrieving template %s bundle', template_id)
|
|
148
148
|
return await self.safe_client.get_template_bundle(remote_id=template_id)
|
|
149
149
|
|
|
150
|
-
async def list_remote_templates(self) ->
|
|
150
|
+
async def list_remote_templates(self) -> list[Template]:
|
|
151
151
|
self.logger.info('Listing remote document templates')
|
|
152
152
|
return await self.safe_client.get_templates()
|
|
153
153
|
|
|
154
|
-
async def list_remote_drafts(self) ->
|
|
154
|
+
async def list_remote_drafts(self) -> list[Template]:
|
|
155
155
|
self.logger.info('Listing remote document template drafts')
|
|
156
156
|
return await self.safe_client.get_drafts()
|
|
157
157
|
|
|
158
|
-
def verify(self) ->
|
|
158
|
+
def verify(self) -> list[ValidationError]:
|
|
159
159
|
template = self.template or self.safe_project.template
|
|
160
160
|
if template is None:
|
|
161
161
|
raise RuntimeError('No template is loaded')
|
|
@@ -165,7 +165,7 @@ class TDKCore:
|
|
|
165
165
|
if self.project is None:
|
|
166
166
|
raise RuntimeError('No template project is initialized')
|
|
167
167
|
self.project.template = self.safe_template
|
|
168
|
-
self.logger.debug(
|
|
168
|
+
self.logger.debug('Initiating storing local template project (force=%s)', force)
|
|
169
169
|
self.project.store(force=force)
|
|
170
170
|
|
|
171
171
|
async def store_remote(self, force: bool):
|
|
@@ -173,8 +173,9 @@ class TDKCore:
|
|
|
173
173
|
self._check_metamodel_version()
|
|
174
174
|
org_id = await self.safe_client.get_organization_id()
|
|
175
175
|
if org_id != self.safe_template.organization_id:
|
|
176
|
-
self.logger.warning(
|
|
177
|
-
|
|
176
|
+
self.logger.warning('There is different organization ID set in the DSW instance'
|
|
177
|
+
' (local: %s, remote: %s)',
|
|
178
|
+
self.safe_template.organization_id, org_id)
|
|
178
179
|
self.remote_id = self.safe_template.id_with_org(org_id)
|
|
179
180
|
template_exists = await self.safe_client.check_draft_exists(remote_id=self.remote_id)
|
|
180
181
|
if template_exists and force:
|
|
@@ -185,26 +186,39 @@ class TDKCore:
|
|
|
185
186
|
template_exists = not result
|
|
186
187
|
|
|
187
188
|
if template_exists:
|
|
188
|
-
# TODO: do not remove if not necessary (make diff?)
|
|
189
189
|
self.logger.info('Updating existing remote document template draft')
|
|
190
|
-
await self.safe_client.update_template_draft(
|
|
190
|
+
await self.safe_client.update_template_draft(
|
|
191
|
+
template=self.safe_template,
|
|
192
|
+
remote_id=self.remote_id,
|
|
193
|
+
)
|
|
191
194
|
self.logger.debug('Retrieving remote assets')
|
|
192
|
-
remote_assets = await self.safe_client.get_template_draft_assets(
|
|
195
|
+
remote_assets = await self.safe_client.get_template_draft_assets(
|
|
196
|
+
remote_id=self.remote_id,
|
|
197
|
+
)
|
|
193
198
|
self.logger.debug('Retrieving remote files')
|
|
194
|
-
remote_files = await self.safe_client.get_template_draft_files(
|
|
195
|
-
|
|
199
|
+
remote_files = await self.safe_client.get_template_draft_files(
|
|
200
|
+
remote_id=self.remote_id,
|
|
201
|
+
)
|
|
202
|
+
await self.cleanup_remote_files(
|
|
203
|
+
remote_assets=remote_assets,
|
|
204
|
+
remote_files=remote_files,
|
|
205
|
+
)
|
|
196
206
|
else:
|
|
197
207
|
self.logger.info('Creating remote document template draft')
|
|
198
|
-
await self.safe_client.create_new_template_draft(
|
|
208
|
+
await self.safe_client.create_new_template_draft(
|
|
209
|
+
template=self.safe_template,
|
|
210
|
+
remote_id=self.remote_id,
|
|
211
|
+
)
|
|
199
212
|
await self.store_remote_files()
|
|
200
213
|
|
|
201
214
|
async def _update_template_file(self, remote_tfile: TemplateFile, local_tfile: TemplateFile,
|
|
202
215
|
project_update: bool = False):
|
|
203
216
|
try:
|
|
204
|
-
self.logger.debug(
|
|
205
|
-
|
|
217
|
+
self.logger.debug('Updating existing remote %s %s (%s) started',
|
|
218
|
+
remote_tfile.remote_type.value, remote_tfile.filename.as_posix(),
|
|
219
|
+
remote_tfile.remote_id)
|
|
206
220
|
local_tfile.remote_id = remote_tfile.remote_id
|
|
207
|
-
if remote_tfile.remote_type == TemplateFileType.
|
|
221
|
+
if remote_tfile.remote_type == TemplateFileType.ASSET:
|
|
208
222
|
result = await self.safe_client.put_template_draft_asset_content(
|
|
209
223
|
remote_id=self.remote_id,
|
|
210
224
|
tfile=local_tfile,
|
|
@@ -214,25 +228,27 @@ class TDKCore:
|
|
|
214
228
|
remote_id=self.remote_id,
|
|
215
229
|
tfile=local_tfile,
|
|
216
230
|
)
|
|
217
|
-
self.logger.debug(
|
|
218
|
-
|
|
219
|
-
|
|
231
|
+
self.logger.debug('Updating existing remote %s %s (%s) finished: %s',
|
|
232
|
+
remote_tfile.remote_type.value, remote_tfile.filename.as_posix(),
|
|
233
|
+
remote_tfile.remote_id, 'ok' if result else 'failed')
|
|
220
234
|
if project_update and result:
|
|
221
235
|
self.safe_project.update_template_file(result)
|
|
222
|
-
except Exception as
|
|
236
|
+
except Exception as e1:
|
|
223
237
|
try:
|
|
224
|
-
self.logger.debug(
|
|
238
|
+
self.logger.debug('Trying to delete/create due to: %s', str(e1))
|
|
225
239
|
await self._delete_template_file(tfile=remote_tfile)
|
|
226
240
|
await self._create_template_file(tfile=local_tfile, project_update=True)
|
|
227
|
-
except Exception as
|
|
228
|
-
self.logger.error(
|
|
229
|
-
|
|
241
|
+
except Exception as e2:
|
|
242
|
+
self.logger.error('Failed to update existing remote %s %s: %s',
|
|
243
|
+
remote_tfile.remote_type.value,
|
|
244
|
+
remote_tfile.filename.as_posix(), e2)
|
|
230
245
|
|
|
231
246
|
async def _delete_template_file(self, tfile: TemplateFile, project_update: bool = False):
|
|
232
247
|
try:
|
|
233
|
-
self.logger.debug(
|
|
234
|
-
|
|
235
|
-
|
|
248
|
+
self.logger.debug('Deleting existing remote %s %s (%s) started',
|
|
249
|
+
tfile.remote_type.value, tfile.filename.as_posix(),
|
|
250
|
+
tfile.remote_id)
|
|
251
|
+
if tfile.remote_type == TemplateFileType.ASSET:
|
|
236
252
|
result = await self.safe_client.delete_template_draft_asset(
|
|
237
253
|
remote_id=self.remote_id,
|
|
238
254
|
asset_id=tfile.remote_id,
|
|
@@ -242,18 +258,19 @@ class TDKCore:
|
|
|
242
258
|
remote_id=self.remote_id,
|
|
243
259
|
file_id=tfile.remote_id,
|
|
244
260
|
)
|
|
245
|
-
self.logger.debug(
|
|
246
|
-
|
|
247
|
-
|
|
261
|
+
self.logger.debug('Deleting existing remote %s %s (%s) finished: %s',
|
|
262
|
+
tfile.remote_type.value, tfile.filename.as_posix(),
|
|
263
|
+
tfile.remote_id, 'ok' if result else 'failed')
|
|
248
264
|
if project_update and result:
|
|
249
265
|
self.safe_project.remove_template_file(tfile.filename)
|
|
250
266
|
except Exception as e:
|
|
251
|
-
self.logger.error(
|
|
252
|
-
|
|
267
|
+
self.logger.error('Failed to delete existing remote %s %s: %s',
|
|
268
|
+
tfile.remote_type.value, tfile.filename.as_posix(), e)
|
|
253
269
|
|
|
254
|
-
async def cleanup_remote_files(self, remote_assets:
|
|
270
|
+
async def cleanup_remote_files(self, remote_assets: list[TemplateFile],
|
|
271
|
+
remote_files: list[TemplateFile]):
|
|
255
272
|
for tfile in self.safe_project.safe_template.files.values():
|
|
256
|
-
self.logger.debug(
|
|
273
|
+
self.logger.debug('Cleaning up remote %s', tfile.filename.as_posix())
|
|
257
274
|
for remote_asset in remote_assets:
|
|
258
275
|
if remote_asset.filename == tfile.filename:
|
|
259
276
|
await self._delete_template_file(tfile=remote_asset, project_update=False)
|
|
@@ -263,60 +280,68 @@ class TDKCore:
|
|
|
263
280
|
|
|
264
281
|
async def _create_template_file(self, tfile: TemplateFile, project_update: bool = False):
|
|
265
282
|
try:
|
|
266
|
-
self.logger.debug(
|
|
267
|
-
|
|
268
|
-
if tfile.remote_type == TemplateFileType.
|
|
269
|
-
result = await self.safe_client.post_template_draft_asset(
|
|
283
|
+
self.logger.debug('Storing remote %s %s started',
|
|
284
|
+
tfile.remote_type.value, tfile.filename.as_posix())
|
|
285
|
+
if tfile.remote_type == TemplateFileType.ASSET:
|
|
286
|
+
result = await self.safe_client.post_template_draft_asset(
|
|
287
|
+
remote_id=self.remote_id,
|
|
288
|
+
tfile=tfile,
|
|
289
|
+
)
|
|
270
290
|
else:
|
|
271
|
-
result = await self.safe_client.post_template_draft_file(
|
|
272
|
-
|
|
273
|
-
|
|
291
|
+
result = await self.safe_client.post_template_draft_file(
|
|
292
|
+
remote_id=self.remote_id,
|
|
293
|
+
tfile=tfile,
|
|
294
|
+
)
|
|
295
|
+
self.logger.debug('Storing remote %s %s finished: %s',
|
|
296
|
+
tfile.remote_type.value, tfile.filename.as_posix(), result.remote_id)
|
|
274
297
|
if project_update and result is not None:
|
|
275
298
|
self.safe_project.update_template_file(result)
|
|
276
299
|
except Exception as e:
|
|
277
|
-
self.logger.error(
|
|
300
|
+
self.logger.error('Failed to store remote %s %s: %s',
|
|
301
|
+
tfile.remote_type.value, tfile.filename.as_posix(), e)
|
|
278
302
|
|
|
279
303
|
async def store_remote_files(self):
|
|
280
304
|
for tfile in self.safe_project.safe_template.files.values():
|
|
281
305
|
tfile.remote_id = None
|
|
282
|
-
tfile.remote_type = TemplateFileType.
|
|
306
|
+
tfile.remote_type = TemplateFileType.FILE if tfile.is_text else TemplateFileType.ASSET
|
|
283
307
|
await self._create_template_file(tfile=tfile, project_update=True)
|
|
284
308
|
|
|
285
309
|
def create_package(self, output: pathlib.Path, force: bool):
|
|
286
310
|
if output.exists() and not force:
|
|
287
311
|
raise RuntimeError(f'File {output} already exists (not forced)')
|
|
288
|
-
self.logger.debug(
|
|
312
|
+
self.logger.debug('Opening ZIP file for write: %s', output.as_posix())
|
|
289
313
|
with zipfile.ZipFile(output, mode='w', compression=zipfile.ZIP_DEFLATED) as pkg:
|
|
290
314
|
descriptor = self.safe_project.safe_template.serialize_remote()
|
|
291
315
|
files = []
|
|
292
316
|
assets = []
|
|
293
317
|
for tfile in self.safe_project.safe_template.files.values():
|
|
294
318
|
if tfile.is_text:
|
|
295
|
-
self.logger.info(
|
|
319
|
+
self.logger.info('Adding template file %s', tfile.filename.as_posix())
|
|
296
320
|
files.append({
|
|
297
321
|
'uuid': str(UUIDGen.generate()),
|
|
298
322
|
'content': tfile.content.decode(encoding=DEFAULT_ENCODING),
|
|
299
323
|
'fileName': str(tfile.filename.as_posix()),
|
|
300
324
|
})
|
|
301
325
|
else:
|
|
302
|
-
self.logger.info(
|
|
326
|
+
self.logger.info('Adding template asset %s', tfile.filename.as_posix())
|
|
303
327
|
assets.append({
|
|
304
328
|
'uuid': str(UUIDGen.generate()),
|
|
305
329
|
'contentType': tfile.content_type,
|
|
306
330
|
'fileName': str(tfile.filename.as_posix()),
|
|
307
331
|
})
|
|
308
|
-
self.logger.debug(
|
|
332
|
+
self.logger.debug('Packaging template asset %s', tfile.filename.as_posix())
|
|
309
333
|
pkg.writestr(f'template/assets/{tfile.filename.as_posix()}', tfile.content)
|
|
310
334
|
descriptor['files'] = files
|
|
311
335
|
descriptor['assets'] = assets
|
|
312
|
-
timestamp = datetime.datetime.
|
|
336
|
+
timestamp = datetime.datetime.now(tz=datetime.UTC).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
|
|
313
337
|
descriptor['createdAt'] = timestamp
|
|
314
338
|
descriptor['updatedAt'] = timestamp
|
|
315
339
|
self.logger.debug('Packaging template.json file')
|
|
316
340
|
pkg.writestr('template/template.json', data=json.dumps(descriptor, indent=4))
|
|
317
341
|
self.logger.debug('ZIP packaging done')
|
|
318
342
|
|
|
319
|
-
|
|
343
|
+
# pylint: disable=too-many-locals
|
|
344
|
+
def extract_package(self, zip_data: bytes, template_dir: pathlib.Path | None, force: bool):
|
|
320
345
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
321
346
|
io_zip = io.BytesIO(zip_data)
|
|
322
347
|
with zipfile.ZipFile(io_zip) as pkg:
|
|
@@ -372,7 +397,7 @@ class TDKCore:
|
|
|
372
397
|
def create_dot_env(self, output: pathlib.Path, force: bool, api_url: str, api_key: str):
|
|
373
398
|
if output.exists():
|
|
374
399
|
if force:
|
|
375
|
-
self.logger.warning(
|
|
400
|
+
self.logger.warning('Overwriting %s (forced)', output.as_posix())
|
|
376
401
|
else:
|
|
377
402
|
raise RuntimeError(f'File {output} already exists (not forced)')
|
|
378
403
|
output.write_text(
|
|
@@ -392,47 +417,49 @@ class TDKCore:
|
|
|
392
417
|
)
|
|
393
418
|
))
|
|
394
419
|
|
|
395
|
-
async def
|
|
420
|
+
async def update_descriptor(self):
|
|
396
421
|
try:
|
|
397
422
|
template_exists = await self.safe_client.check_draft_exists(
|
|
398
423
|
remote_id=self.remote_id,
|
|
399
424
|
)
|
|
400
425
|
if template_exists:
|
|
401
|
-
self.logger.info(
|
|
402
|
-
|
|
426
|
+
self.logger.info('Updating existing remote document template draft %s',
|
|
427
|
+
self.safe_project.safe_template.id)
|
|
403
428
|
await self.safe_client.update_template_draft(
|
|
404
429
|
template=self.safe_project.safe_template,
|
|
405
430
|
remote_id=self.remote_id,
|
|
406
431
|
)
|
|
407
432
|
else:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
f'does not exist on remote - full sync')
|
|
433
|
+
self.logger.info('Document template draft %s does not exist on remote - full sync',
|
|
434
|
+
self.safe_project.safe_template.id)
|
|
411
435
|
await self.store_remote(force=False)
|
|
412
436
|
except DSWCommunicationError as e:
|
|
413
|
-
self.logger.error(
|
|
414
|
-
|
|
437
|
+
self.logger.error('Failed to update document template draft %s: %s',
|
|
438
|
+
self.safe_project.safe_template.id, e.message)
|
|
415
439
|
except Exception as e:
|
|
416
|
-
self.logger.error(
|
|
417
|
-
|
|
440
|
+
self.logger.error('Failed to update document template draft %s: %s',
|
|
441
|
+
self.safe_project.safe_template.id, e)
|
|
418
442
|
|
|
419
|
-
async def
|
|
443
|
+
async def delete_file(self, filepath: pathlib.Path):
|
|
420
444
|
if not filepath.is_file():
|
|
421
|
-
self.logger.debug(
|
|
445
|
+
self.logger.debug('%s is not a regular file - skipping',
|
|
446
|
+
filepath.as_posix())
|
|
422
447
|
return
|
|
423
448
|
try:
|
|
424
449
|
tfile = self.safe_project.get_template_file(filepath=filepath)
|
|
425
450
|
if tfile is None:
|
|
426
|
-
|
|
427
|
-
|
|
451
|
+
self.logger.info('File %s not tracked currently - skipping',
|
|
452
|
+
filepath.as_posix())
|
|
428
453
|
return
|
|
429
454
|
await self._delete_template_file(tfile=tfile, project_update=True)
|
|
430
455
|
except Exception as e:
|
|
431
|
-
self.logger.error(
|
|
456
|
+
self.logger.error('Failed to delete file %s: %s',
|
|
457
|
+
filepath.as_posix(), e)
|
|
432
458
|
|
|
433
|
-
async def
|
|
459
|
+
async def update_file(self, filepath: pathlib.Path):
|
|
434
460
|
if not filepath.is_file():
|
|
435
|
-
self.logger.debug(
|
|
461
|
+
self.logger.debug('%s is not a regular file - skipping',
|
|
462
|
+
filepath.as_posix())
|
|
436
463
|
return
|
|
437
464
|
try:
|
|
438
465
|
remote_tfile = self.safe_project.get_template_file(filepath=filepath)
|
|
@@ -442,30 +469,30 @@ class TDKCore:
|
|
|
442
469
|
else:
|
|
443
470
|
await self._create_template_file(tfile=local_tfile, project_update=True)
|
|
444
471
|
except Exception as e:
|
|
445
|
-
self.logger.error(
|
|
472
|
+
self.logger.error('Failed to update file %s: %s', filepath.as_posix(), e)
|
|
446
473
|
|
|
447
|
-
async def process_changes(self, changes:
|
|
474
|
+
async def process_changes(self, changes: list[ChangeItem], force: bool):
|
|
448
475
|
self.changes_processor.clear()
|
|
449
476
|
try:
|
|
450
477
|
await self.changes_processor.process_changes(changes, force)
|
|
451
478
|
except Exception as e:
|
|
452
|
-
self.logger.error(
|
|
479
|
+
self.logger.error('Failed to process changes: %s', e)
|
|
453
480
|
|
|
454
481
|
|
|
455
482
|
class ChangesProcessor:
|
|
456
483
|
|
|
457
484
|
def __init__(self, tdk: TDKCore):
|
|
458
|
-
self.tdk = tdk
|
|
459
|
-
self.descriptor_change
|
|
460
|
-
self.readme_change
|
|
461
|
-
self.file_changes
|
|
485
|
+
self.tdk: TDKCore = tdk
|
|
486
|
+
self.descriptor_change: ChangeItem | None = None
|
|
487
|
+
self.readme_change: ChangeItem | None = None
|
|
488
|
+
self.file_changes: list[ChangeItem] = []
|
|
462
489
|
|
|
463
490
|
def clear(self):
|
|
464
491
|
self.descriptor_change = None
|
|
465
492
|
self.readme_change = None
|
|
466
493
|
self.file_changes = []
|
|
467
494
|
|
|
468
|
-
def _split_changes(self, changes:
|
|
495
|
+
def _split_changes(self, changes: list[ChangeItem]):
|
|
469
496
|
for change in changes:
|
|
470
497
|
if change[1] == self.tdk.safe_project.descriptor_path:
|
|
471
498
|
self.descriptor_change = change
|
|
@@ -478,30 +505,32 @@ class ChangesProcessor:
|
|
|
478
505
|
deleted = set()
|
|
479
506
|
updated = set()
|
|
480
507
|
for file_change in self.file_changes:
|
|
481
|
-
self.tdk.logger.debug(
|
|
508
|
+
self.tdk.logger.debug('Processing: %s',
|
|
509
|
+
_change(file_change, self.tdk.safe_project.template_dir))
|
|
482
510
|
change_type = file_change[0]
|
|
483
511
|
filepath = file_change[1]
|
|
484
512
|
if change_type == watchfiles.Change.deleted and filepath not in deleted:
|
|
485
513
|
self.tdk.logger.debug('Scheduling delete operation')
|
|
486
514
|
deleted.add(filepath)
|
|
487
|
-
await self.tdk.
|
|
515
|
+
await self.tdk.delete_file(filepath)
|
|
488
516
|
elif filepath not in updated:
|
|
489
517
|
self.tdk.logger.debug('Scheduling update operation')
|
|
490
518
|
updated.add(filepath)
|
|
491
|
-
await self.tdk.
|
|
519
|
+
await self.tdk.update_file(filepath)
|
|
492
520
|
|
|
493
521
|
async def _reload_descriptor(self, force: bool) -> bool:
|
|
494
522
|
if self.descriptor_change is None:
|
|
495
523
|
return False
|
|
496
524
|
if self.descriptor_change[0] == watchfiles.Change.deleted:
|
|
497
|
-
raise RuntimeError(f'Deleted
|
|
498
|
-
self.tdk.logger.debug(
|
|
525
|
+
raise RuntimeError(f'Deleted {self.tdk.safe_project.descriptor_path} ... the end')
|
|
526
|
+
self.tdk.logger.debug('Reloading %s file', TemplateProject.TEMPLATE_FILE)
|
|
499
527
|
previous_id = self.tdk.safe_project.safe_template.id
|
|
500
528
|
self.tdk.safe_project.load_descriptor()
|
|
501
529
|
self.tdk.safe_project.load_readme()
|
|
502
530
|
new_id = self.tdk.safe_project.safe_template.id
|
|
503
531
|
if new_id != previous_id:
|
|
504
|
-
self.tdk.logger.warning(
|
|
532
|
+
self.tdk.logger.warning('Template ID changed from %s to %s',
|
|
533
|
+
previous_id, new_id)
|
|
505
534
|
self.tdk.safe_project.load()
|
|
506
535
|
await self.tdk.store_remote(force=force)
|
|
507
536
|
self.tdk.logger.info('Template fully reloaded... waiting for new changes')
|
|
@@ -520,10 +549,10 @@ class ChangesProcessor:
|
|
|
520
549
|
async def _update_descriptor(self):
|
|
521
550
|
if self.readme_change is not None or self.descriptor_change is not None:
|
|
522
551
|
self.tdk.logger.debug('Updating template descriptor (metadata)')
|
|
523
|
-
await self.tdk.
|
|
552
|
+
await self.tdk.update_descriptor()
|
|
524
553
|
self.tdk.safe_project.template = self.tdk.safe_template
|
|
525
554
|
|
|
526
|
-
async def process_changes(self, changes:
|
|
555
|
+
async def process_changes(self, changes: list[ChangeItem], force: bool):
|
|
527
556
|
self._split_changes(changes)
|
|
528
557
|
full_reload = await self._reload_descriptor(force)
|
|
529
558
|
if not full_reload:
|