Skip to content

Commit 891b4fc

Browse files
committed
Move the file related operations in file_utils
1 parent f7d9413 commit 891b4fc

File tree

2 files changed

+89
-56
lines changed

2 files changed

+89
-56
lines changed

libqfieldsync/offline_converter.py

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@
1717
***************************************************************************/
1818
"""
1919

20-
import re
21-
import shutil
2220
import tempfile
2321
from enum import Enum
24-
from glob import glob
2522
from pathlib import Path
2623
from typing import Dict, List, Optional, TypedDict, Union, cast
2724

@@ -52,7 +49,9 @@
5249
from .offliners import BaseOffliner
5350
from .project import ProjectConfiguration, ProjectProperties
5451
from .utils.file_utils import (
52+
copy_additional_project_files,
5553
copy_attachments,
54+
get_project_like_files,
5655
set_relative_embed_layer_symbols_on_project,
5756
)
5857
from .utils.logger import logger
@@ -198,16 +197,14 @@ def _get_additional_project_files(self, project: QgsProject) -> List[str]:
198197
):
199198
additional_project_files.append(str(image_decoration_path))
200199

201-
# Check for project plugin asset
202-
plugin_file = Path("{}.qml".format(str(self.original_filename)[:-4])) # noqa: UP032
203-
if plugin_file.exists():
204-
additional_project_files.append(str(plugin_file))
205-
206-
# Check for project translations asset
207-
for translation_file in glob(
208-
f"{str(self.original_filename)[:-4]}_[A-Za-z][A-Za-z].qm"
209-
):
210-
additional_project_files.append(str(translation_file))
200+
# Get project plugin asset
201+
additional_project_files += get_project_like_files(
202+
self.original_filename, ".qml"
203+
)
204+
# Get project translations assets
205+
additional_project_files += get_project_like_files(
206+
self.original_filename, "_[A-Za-z][A-Za-z].qm"
207+
)
211208

212209
return additional_project_files
213210

@@ -362,49 +359,11 @@ def _convert(self, project: QgsProject) -> None: # noqa: PLR0912, PLR0915
362359

363360
# copy additional project files (e.g. layout images, symbology images, etc)
364361
if additional_project_files:
365-
project_path = Path(project.fileName()).parent
366-
for additional_project_file in additional_project_files:
367-
additional_project_file_path = Path(additional_project_file)
368-
additional_project_file_name = additional_project_file_path.name
369-
additional_project_file_relative_path = (
370-
additional_project_file_path.relative_to(project_path)
371-
)
372-
373-
destination_file = self._export_filename.parent.joinpath(
374-
additional_project_file_relative_path
375-
).resolve()
376-
destination_file.parent.mkdir(parents=True, exist_ok=True)
377-
378-
# Project plugins and translation files require for their file name
379-
# to match that of their associated project file (e.g myproject.qgs,
380-
# myproject_bg.qm for a translation file and myproject.qml for a
381-
# project plugin). We must therefore adapt these file names to match
382-
# the generated project file name
383-
original_project_filename_without_extension = str(
384-
self.original_filename
385-
)[:-4]
386-
export_project_filename_without_extension = str(
387-
export_project_filename.name
388-
)[:-4]
389-
if (
390-
str(additional_project_file_path)
391-
== f"{original_project_filename_without_extension}.qml"
392-
):
393-
destination_file = destination_file.parent.joinpath(
394-
f"{export_project_filename_without_extension}.qml"
395-
)
396-
397-
elif additional_project_file_name.endswith(".qm"):
398-
match = re.match(
399-
rf"^{re.escape(original_project_filename_without_extension)}(_[A-Za-z]{{2}}\.qm)$",
400-
str(additional_project_file_path),
401-
)
402-
if match:
403-
destination_file = destination_file.parent.joinpath(
404-
f"{export_project_filename_without_extension}{match.group(1)}"
405-
)
406-
407-
shutil.copy(additional_project_file, str(destination_file))
362+
copy_additional_project_files(
363+
project.fileName(),
364+
self._export_filename,
365+
additional_project_files,
366+
)
408367

409368
# save the offline project twice so that the offline plugin can "know" that it's a relative path
410369
QgsProject.instance().write(str(export_project_filename))

libqfieldsync/utils/file_utils.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"""
1919

2020
import base64
21+
import glob
2122
import hashlib
2223
import os
2324
import platform
@@ -340,3 +341,76 @@ def set_relative_embed_layer_symbols_on_project( # noqa: PLR0912
340341
renderer.updateCategorySymbol(index, symbol)
341342

342343
layer.setRenderer(renderer)
344+
345+
346+
def get_project_like_files(
347+
project_filename: Union[str, Path], glob_pattern: str
348+
) -> List[str]:
349+
"""
350+
Get the list of files with names similar to given project name and glob pattern.
351+
352+
Args:
353+
project_filename: The original filename of the project.
354+
glob_pattern: The glob pattern to search for similar files. Note that the pattern does not support regex such as `[a-z]{2}`.
355+
356+
"""
357+
project_filename = Path(project_filename)
358+
project_like_files = []
359+
360+
assert project_filename.suffix in (".qgs", ".qgz")
361+
362+
escaped_stem_name = glob.escape(project_filename.stem)
363+
364+
# Check for project translations asset with two-letter language code
365+
for project_like_file in project_filename.parent.glob(
366+
f"{escaped_stem_name}{glob_pattern}",
367+
# root_dir=,
368+
):
369+
project_like_files.append(str(project_like_file))
370+
371+
return project_like_files
372+
373+
374+
def copy_additional_project_files(
375+
source_project_filename: Union[str, Path],
376+
export_project_filename: Union[str, Path],
377+
additional_project_files: List[str],
378+
):
379+
source_project_filename = Path(source_project_filename)
380+
export_project_filename = Path(export_project_filename)
381+
382+
for additional_project_file in additional_project_files:
383+
additional_project_file_path = Path(additional_project_file)
384+
additional_project_file_name = additional_project_file_path.name
385+
additional_project_file_relative_path = (
386+
additional_project_file_path.relative_to(source_project_filename.parent)
387+
)
388+
389+
destination_file = export_project_filename.parent.joinpath(
390+
additional_project_file_relative_path
391+
).resolve()
392+
destination_file.parent.mkdir(parents=True, exist_ok=True)
393+
394+
# Project plugins and translation files require for their file name
395+
# to match that of their associated project file (e.g myproject.qgs,
396+
# myproject_bg.qm for a translation file and myproject.qml for a
397+
# project plugin). We must therefore adapt these file names to match
398+
# the generated project file name
399+
original_project_stem_name = source_project_filename.stem
400+
export_project_stem_name = export_project_filename.stem
401+
if str(additional_project_file_path) == f"{original_project_stem_name}.qml":
402+
destination_file = destination_file.parent.joinpath(
403+
f"{export_project_stem_name}.qml"
404+
)
405+
406+
elif additional_project_file_name.endswith(".qm"):
407+
match = re.match(
408+
rf"^{re.escape(original_project_stem_name)}(_[A-Za-z]{{2}}\.qm)$",
409+
str(additional_project_file_path),
410+
)
411+
if match:
412+
destination_file = destination_file.parent.joinpath(
413+
f"{export_project_stem_name}{match.group(1)}"
414+
)
415+
416+
shutil.copy(additional_project_file, str(destination_file))

0 commit comments

Comments
 (0)