Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions libqfieldsync/offline_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
***************************************************************************/
"""

import shutil
import tempfile
from enum import Enum
from pathlib import Path
Expand Down Expand Up @@ -50,7 +49,9 @@
from .offliners import BaseOffliner
from .project import ProjectConfiguration, ProjectProperties
from .utils.file_utils import (
copy_additional_project_files,
copy_attachments,
get_project_like_files,
set_relative_embed_layer_symbols_on_project,
)
from .utils.logger import logger
Expand Down Expand Up @@ -196,10 +197,14 @@ def _get_additional_project_files(self, project: QgsProject) -> List[str]:
):
additional_project_files.append(str(image_decoration_path))

# Check for project plugin asset
plugin_file = Path("{}.qml".format(str(self.original_filename)[:-4])) # noqa: UP032
if plugin_file.exists():
additional_project_files.append(str(plugin_file))
# Get project plugin asset
additional_project_files += get_project_like_files(
self.original_filename, ".qml"
)
# Get project translations assets
additional_project_files += get_project_like_files(
self.original_filename, "_[A-Za-z][A-Za-z].qm"
)

return additional_project_files

Expand Down Expand Up @@ -354,15 +359,11 @@ def _convert(self, project: QgsProject) -> None: # noqa: PLR0912, PLR0915

# copy additional project files (e.g. layout images, symbology images, etc)
if additional_project_files:
project_path = Path(project.fileName()).parent
for additional_project_file in additional_project_files:
additional_project_file_path = Path(additional_project_file)
relative_path = additional_project_file_path.relative_to(project_path)
destination_file = self._export_filename.parent.joinpath(
relative_path
).resolve()
destination_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(additional_project_file, str(destination_file))
copy_additional_project_files(
project.fileName(),
self._export_filename,
additional_project_files,
)

# save the offline project twice so that the offline plugin can "know" that it's a relative path
QgsProject.instance().write(str(export_project_filename))
Expand Down
74 changes: 74 additions & 0 deletions libqfieldsync/utils/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""

import base64
import glob
import hashlib
import os
import platform
Expand Down Expand Up @@ -340,3 +341,76 @@ def set_relative_embed_layer_symbols_on_project( # noqa: PLR0912
renderer.updateCategorySymbol(index, symbol)

layer.setRenderer(renderer)


def get_project_like_files(
project_filename: Union[str, Path], glob_pattern: str
) -> List[str]:
"""
Get the list of files with names similar to given project name and glob pattern.

Args:
project_filename: The original filename of the project.
glob_pattern: The glob pattern to search for similar files. Note that the pattern does not support regex such as `[a-z]{2}`.

"""
project_filename = Path(project_filename)
project_like_files = []

assert project_filename.suffix in (".qgs", ".qgz")

escaped_stem_name = glob.escape(project_filename.stem)

# Check for project translations asset with two-letter language code
for project_like_file in project_filename.parent.glob(
f"{escaped_stem_name}{glob_pattern}",
# root_dir=,
):
project_like_files.append(str(project_like_file))

return project_like_files


def copy_additional_project_files(
source_project_filename: Union[str, Path],
export_project_filename: Union[str, Path],
additional_project_files: List[str],
):
source_project_filename = Path(source_project_filename)
export_project_filename = Path(export_project_filename)

for additional_project_file in additional_project_files:
additional_project_file_path = Path(additional_project_file)
additional_project_file_name = additional_project_file_path.name
additional_project_file_relative_path = (
additional_project_file_path.relative_to(source_project_filename.parent)
)

destination_file = export_project_filename.parent.joinpath(
additional_project_file_relative_path
).resolve()
destination_file.parent.mkdir(parents=True, exist_ok=True)

# Project plugins and translation files require for their file name
# to match that of their associated project file (e.g myproject.qgs,
# myproject_bg.qm for a translation file and myproject.qml for a
# project plugin). We must therefore adapt these file names to match
# the generated project file name
original_project_stem_name = source_project_filename.stem
export_project_stem_name = export_project_filename.stem
if str(additional_project_file_name) == f"{original_project_stem_name}.qml":
destination_file = destination_file.parent.joinpath(
f"{export_project_stem_name}.qml"
)

elif additional_project_file_name.endswith(".qm"):
match = re.match(
rf"^{re.escape(original_project_stem_name)}(_[A-Za-z]{{2}}\.qm)$",
str(additional_project_file_name),
)
if match:
destination_file = destination_file.parent.joinpath(
f"{export_project_stem_name}{match.group(1)}"
)

shutil.copy(additional_project_file, str(destination_file))
Empty file.
Empty file.
4 changes: 3 additions & 1 deletion tests/test_offline_converter_minioffliner.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ def test_assets(self):
self.assertTrue(
self.target_dir.joinpath("assets", "qfield_for_qgis.png").exists()
)
self.assertTrue(self.target_dir.joinpath("project.qml").exists())
self.assertTrue(self.target_dir.joinpath("project_qfield.qml").exists())
self.assertTrue(self.target_dir.joinpath("project_qfield_fr.qm").exists())
self.assertTrue(self.target_dir.joinpath("project_qfield_de.qm").exists())

def test_primary_keys_custom_property(self):
shutil.copytree(
Expand Down
Loading