Skip to content

Commit dd03a38

Browse files
committed
Introduce UploadChanges class and split method
1 parent 9fa6c04 commit dd03a38

File tree

4 files changed

+57
-48
lines changed

4 files changed

+57
-48
lines changed

mergin/client_push.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,38 @@ def upload_blocking(self, mc, mp):
8383
raise ClientError("Mismatch between uploaded file chunk {} and local one".format(self.chunk_id))
8484

8585

86+
class UploadChanges:
87+
def __init__(self, added=None, updated=None, removed=None):
88+
self.added = added or []
89+
self.updated = updated or []
90+
self.removed = removed or []
91+
self.renamed = []
92+
93+
def is_empty(self):
94+
return not (self.added or self.updated or self.removed or self.renamed)
95+
96+
def split(self):
97+
blocking = UploadChanges()
98+
non_blocking = UploadChanges()
99+
100+
for file in self.added:
101+
target = blocking if is_qgis_file(file["path"]) or is_versioned_file(file["path"]) else non_blocking
102+
target.added.append(file)
103+
104+
for file in self.updated:
105+
blocking.updated.append(file)
106+
107+
for file in self.removed:
108+
blocking.removed.append(file)
109+
110+
result = {}
111+
if not blocking.is_empty():
112+
result["blocking"] = blocking
113+
if not non_blocking.is_empty():
114+
result["non_blocking"] = non_blocking
115+
return result
116+
117+
86118
def push_project_async(mc, directory):
87119
"""Starts push of a project and returns pending upload job"""
88120

@@ -124,21 +156,22 @@ def push_project_async(mc, directory):
124156
changes = mp.get_push_changes()
125157
changes = filter_changes(mc, project_info, changes)
126158

127-
blocking_changes, non_blocking_changes = split_changes(changes)
159+
blocking_changes, non_blocking_changes = changes.split()
128160

129161
blocking_job = (
130162
_prepare_upload_job(mp, mc, project_path, local_version, blocking_changes)
131163
if any(len(v) for v in blocking_changes.values())
132164
else None
133165
)
134166
non_blocking_job = (
135-
_prepare_upload_job(mp, mc, project_path, local_version, non_blocking_changes)
167+
_prepare_upload_job(mp, mc, project_path, local_version, non_blocking_changes)
136168
if any(len(v) for v in non_blocking_changes.values())
137169
else None
138170
)
139171

140172
return blocking_job, non_blocking_job
141173

174+
142175
def _prepare_upload_job(mp, mc, project_path, local_version, changes):
143176
mp.log.debug("push changes:\n" + pprint.pformat(changes))
144177

@@ -226,6 +259,7 @@ def _prepare_upload_job(mp, mc, project_path, local_version, changes):
226259
job.futures.append(future)
227260
return job
228261

262+
229263
def push_project_wait(job):
230264
"""blocks until all upload tasks are finished"""
231265

@@ -351,25 +385,3 @@ def remove_diff_files(job) -> None:
351385
if os.path.exists(diff_file):
352386
os.remove(diff_file)
353387

354-
355-
def split_changes(changes):
356-
"""Split changes into blocking and non-blocking.
357-
358-
Blocking criteria:
359-
- any updated files
360-
- any removed files
361-
- added files that are .gpkg or .qgz (.ggs)
362-
"""
363-
blocking = non_blocking = {"added": [], "updated": [], "removed": [], "renamed": []}
364-
365-
blocking["updated"] = changes["updated"]
366-
blocking["removed"] = changes["removed"]
367-
blocking["renamed"] = changes["renamed"]
368-
369-
for f in changes["added"]:
370-
if is_qgis_file(f["path"]) or is_versioned_file(f["path"]):
371-
blocking["added"].append(f)
372-
else:
373-
non_blocking["added"].append(f)
374-
375-
return blocking, non_blocking

mergin/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
from enum import Enum
33

4-
CHUNK_SIZE = 10 * 1024 * 1024
4+
CHUNK_SIZE = 100 * 1024 * 1024
55

66
# there is an upper limit for chunk size on server, ideally should be requested from there once implemented
77
UPLOAD_CHUNK_SIZE = 10 * 1024 * 1024

mergin/editor.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from itertools import filterfalse
22
from typing import Callable, Dict, List
33

4+
from .client_push import UploadChanges
45
from .utils import is_mergin_config, is_qgis_file, is_versioned_file
56

67
EDITOR_ROLE_NAME = "editor"
@@ -24,7 +25,7 @@ def is_editor_enabled(mc, project_info: dict) -> bool:
2425
return server_support and project_role == EDITOR_ROLE_NAME
2526

2627

27-
def _apply_editor_filters(changes: Dict[str, List[dict]]) -> Dict[str, List[dict]]:
28+
def _apply_editor_filters(changes: UploadChanges) -> UploadChanges:
2829
"""
2930
Applies editor-specific filters to the changes dictionary, removing any changes to files that are not in the editor's list of allowed files.
3031
@@ -36,11 +37,11 @@ def _apply_editor_filters(changes: Dict[str, List[dict]]) -> Dict[str, List[dict
3637
"""
3738
updated = changes.get("updated", [])
3839

39-
changes["updated"] = list(filterfalse(_disallowed_changes, updated))
40+
changes.updated = list(filterfalse(_disallowed_changes, updated))
4041
return changes
4142

4243

43-
def filter_changes(mc, project_info: dict, changes: Dict[str, List[dict]]) -> Dict[str, List[dict]]:
44+
def filter_changes(mc, project_info: dict, changes: UploadChanges) -> UploadChanges:
4445
"""
4546
Filters the given changes dictionary based on the editor's enabled state.
4647

mergin/merginproject.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from datetime import datetime
1010
from dateutil.tz import tzlocal
1111

12+
from .client_push import UploadChanges
1213
from .editor import prevent_conflicted_copy
1314

1415
from .common import UPLOAD_CHUNK_SIZE, InvalidProject, ClientError
@@ -314,23 +315,13 @@ def inspect_files(self):
314315
)
315316
return files_meta
316317

317-
def compare_file_sets(self, origin, current):
318+
def compare_file_sets(self, origin, current) -> UploadChanges:
318319
"""
319-
Helper function to calculate difference between two sets of files metadata using file names and checksums.
320+
Calculate difference between two sets of file metadata using file names and checksums.
320321
321-
:Example:
322-
323-
>>> origin = [{'checksum': '08b0e8caddafe74bf5c11a45f65cedf974210fed', 'path': 'base.gpkg', 'size': 2793, 'mtime': '2019-08-26T11:08:34.051221+02:00'}]
324-
>>> current = [{'checksum': 'c9a4fd2afd513a97aba19d450396a4c9df8b2ba4', 'path': 'test.qgs', 'size': 31980, 'mtime': '2019-08-26T11:09:30.051221+02:00'}]
325-
>>> self.compare_file_sets(origin, current)
326-
{"added": [{'checksum': 'c9a4fd2afd513a97aba19d450396a4c9df8b2ba4', 'path': 'test.qgs', 'size': 31980, 'mtime': '2019-08-26T11:09:30.051221+02:00'}], "removed": [[{'checksum': '08b0e8caddafe74bf5c11a45f65cedf974210fed', 'path': 'base.gpkg', 'size': 2793, 'mtime': '2019-08-26T11:08:34.051221+02:00'}]], "renamed": [], "updated": []}
327-
328-
:param origin: origin set of files metadata
329-
:type origin: list[dict]
330-
:param current: current set of files metadata to be compared against origin
331-
:type current: list[dict]
332-
:returns: changes between two sets with change type
333-
:rtype: dict[str, list[dict]]'
322+
:param origin: List of original file metadata
323+
:param current: List of current file metadata
324+
:return: UploadChanges instance with added, updated, removed
334325
"""
335326
origin_map = {f["path"]: f for f in origin}
336327
current_map = {f["path"]: f for f in current}
@@ -347,7 +338,12 @@ def compare_file_sets(self, origin, current):
347338
f["origin_checksum"] = origin_map[path]["checksum"]
348339
updated.append(f)
349340

350-
return {"renamed": [], "added": added, "removed": removed, "updated": updated}
341+
return UploadChanges(
342+
added=added,
343+
updated=updated,
344+
removed=removed,
345+
)
346+
351347

352348
def get_pull_changes(self, server_files):
353349
"""
@@ -405,7 +401,7 @@ def get_pull_changes(self, server_files):
405401
changes["updated"] = [f for f in changes["updated"] if f not in not_updated]
406402
return changes
407403

408-
def get_push_changes(self):
404+
def get_push_changes(self) -> UploadChanges:
409405
"""
410406
Calculate changes needed to be pushed to server.
411407
@@ -427,9 +423,9 @@ def get_push_changes(self):
427423
file["checksum"] = checksum
428424
file["chunks"] = [str(uuid.uuid4()) for i in range(math.ceil(file["size"] / UPLOAD_CHUNK_SIZE))]
429425

430-
# need to check for for real changes in geodiff files using geodiff tool (comparing checksum is not enough)
426+
# need to check for real changes in geodiff files using geodiff tool (comparing checksum is not enough)
431427
not_updated = []
432-
for file in changes["updated"]:
428+
for file in changes.updated:
433429
path = file["path"]
434430
if not self.is_versioned_file(path):
435431
continue
@@ -463,7 +459,7 @@ def get_push_changes(self):
463459
# we will need to do full upload of the file
464460
pass
465461

466-
changes["updated"] = [f for f in changes["updated"] if f not in not_updated]
462+
changes.updated = [f for f in changes.updated if f not in not_updated]
467463
return changes
468464

469465
def copy_versioned_file_for_upload(self, f, tmp_dir):

0 commit comments

Comments
 (0)