Skip to content

Commit 8e3f2ec

Browse files
committed
solve base file missing
1 parent db7be6c commit 8e3f2ec

File tree

3 files changed

+55
-43
lines changed

3 files changed

+55
-43
lines changed

mergin/client_pull.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -531,49 +531,63 @@ def pull_project_async(mc, directory) -> Optional[PullJob]:
531531
# list of FileToMerge instances, which consists of destination path and list of download items
532532
merge_files = []
533533
diff_files = []
534-
# make sure we can update geodiff reference files (aka. basefiles) with diffs or
535-
# download their full versions so we have them up-to-date for applying changes
536534
basefiles_to_patch = [] # list of tuples (relative path within project, list of diff files in temp dir to apply)
537535
pull_actions = []
538536
local_delta = mp.get_local_delta(tmp_dir.name)
537+
# Converting local to PullActions
539538
for item in delta.items:
539+
# find corresponding local delta item
540540
local_item = next((i for i in local_delta if i.path == item.path), None)
541-
pull_action = mp.get_pull_action(item.change, local_item.change if local_item else None)
542-
if not pull_action:
541+
local_item_change = local_item.change if local_item else None
542+
543+
# compare server and local changes to decide what to do in pull
544+
pull_action_type = mp.get_pull_action(item.change, local_item_change)
545+
if not pull_action_type:
543546
continue # no action needed
544547

545-
pull_actions.append(PullAction(pull_action, item, local_item))
546-
if pull_action == PullActionType.APPLY_DIFF or (
547-
pull_action == PullActionType.COPY_CONFLICT and item.change == DeltaChangeType.UPDATE_DIFF
548+
pull_action = PullAction(pull_action_type, item, local_item)
549+
if pull_action_type == PullActionType.APPLY_DIFF or (
550+
pull_action_type == PullActionType.COPY_CONFLICT and item.change == DeltaChangeType.UPDATE_DIFF
548551
):
552+
basefile = mp.fpath_meta(item.path)
553+
if not os.path.exists(basefile):
554+
# The basefile does not exist for some reason. This should not happen normally (maybe user removed the file
555+
# or we removed it within previous pull because we failed to apply patch the older version for some reason).
556+
# But it's not a problem - we will download the newest version and we're sorted.
557+
mp.log.info(f"missing base file for {item.path} -> going to download it (version {server_version})")
558+
items = get_download_items(item.path, item.size, server_version, tmp_dir.name)
559+
dest_file_path = mp.fpath(item.path, tmp_dir.name)
560+
merge_files.append(FileToMerge(dest_file_path, items))
561+
562+
# Force use COPY action to apply the new version instead of trying to apply diffs
563+
# We are not able to get local changes anyway as base file is missing
564+
pull_action.type = PullActionType.COPY_CONFLICT
565+
549566
# if we have diff to apply, let's download the diff files
550567
# if we have conflict and diff update, download the diff files
551-
if v2_pull:
568+
elif v2_pull:
552569
diff_files.extend(
553570
[
554571
DownloadDiffQueueItem(diff_item.id, os.path.join(tmp_dir.name, diff_item.id))
555572
for diff_item in item.diffs
556573
]
557574
)
575+
basefiles_to_patch.append((item.path, [diff.id for diff in item.diffs]))
576+
558577
else:
578+
# fallback for diff files using v1 endpoint /raw
559579
diff_merge_files = get_diff_merge_files(item, tmp_dir.name)
560580
merge_files.extend(diff_merge_files)
581+
basefiles_to_patch.append((item.path, [diff.id for diff in item.diffs]))
582+
561583
# let's check the base file existence
562-
basefile = mp.fpath_meta(item.path)
563-
if not os.path.exists(basefile):
564-
# The basefile does not exist for some reason. This should not happen normally (maybe user removed the file
565-
# or we removed it within previous pull because we failed to apply patch the older version for some reason).
566-
# But it's not a problem - we will download the newest version and we're sorted.
567-
mp.log.info(f"missing base file for {item.path} -> going to download it (version {server_version})")
568-
items = get_download_items(item.path, item.size, server_version, tmp_dir.name)
569-
dest_file_path = mp.fpath(item.path, tmp_dir.name)
570-
merge_files.append(FileToMerge(dest_file_path, items))
571-
basefiles_to_patch.append((item.path, [diff.id for diff in item.diffs]))
572-
elif pull_action == PullActionType.COPY or pull_action == PullActionType.COPY_CONFLICT:
584+
elif pull_action_type == PullActionType.COPY or pull_action_type == PullActionType.COPY_CONFLICT:
573585
# simply download the server version of the files
574586
dest_file_path = prepare_file_destination(tmp_dir.name, item.path)
575587
download_items = get_download_items(item.path, item.size, server_version, tmp_dir.name)
576588
merge_files.append(FileToMerge(dest_file_path, download_items))
589+
590+
pull_actions.append(pull_action)
577591
# Do nothing for DELETE actions
578592

579593
# make a single list of items to download
@@ -693,7 +707,7 @@ def pull_project_finalize(job: PullJob):
693707
basefile = job.mp.fpath_meta(file_path)
694708
server_file = job.mp.fpath(file_path, job.tmp_dir.name)
695709

696-
shutil.copy(basefile, server_file)
710+
job.mp.geodiff.make_copy_sqlite(basefile, server_file)
697711
diffs = [job.mp.fpath(f, job.tmp_dir.name) for f in file_diffs]
698712
patch_error = job.mp.apply_diffs(server_file, diffs)
699713
if patch_error:
@@ -709,6 +723,7 @@ def pull_project_finalize(job: PullJob):
709723
os.remove(basefile)
710724
raise ClientError("Cannot patch basefile {}! Please try syncing again.".format(basefile))
711725
conflicts = []
726+
job.mp.log.info(f"--- applying pull actions {job.pull_actions}")
712727
try:
713728
if job.pull_actions:
714729
conflicts = job.mp.apply_pull_actions(job.pull_actions, job.tmp_dir.name, job.project_info, job.mc)

mergin/merginproject.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,6 @@ def get_local_delta(self, diff_directory: str) -> List[ProjectDeltaItem]:
633633
# probably the database schema has been modified if geodiff cannot create changeset.
634634
# we will need to do full upload of the file
635635
pass
636-
print(delta_item)
637636
result.append(delta_item)
638637

639638
return result
@@ -732,9 +731,7 @@ def get_list_of_push_changes(self, push_changes):
732731
pass
733732
return changes
734733

735-
def apply_pull_actions(
736-
self, actions: List[PullAction], downloaded_files_directory: str, server_project: dict, mc
737-
) -> List[str]:
734+
def apply_pull_actions(self, actions: List[PullAction], download_dir: str, server_project: dict, mc) -> List[str]:
738735
"""
739736
Apply pull actions for files.
740737
@@ -743,8 +740,8 @@ def apply_pull_actions(
743740
744741
:param actions: list of pull actions
745742
:type actions: List[PullAction]
746-
:param downloaded_files_directory: directory with downloaded files from server
747-
:type downloaded_files_directory: str
743+
:param download_dir: directory with downloaded files from server
744+
:type download_dir: str
748745
:param server_project: project metadata from the server
749746
:type server_project: dict
750747
:param mc: mergin client
@@ -756,44 +753,42 @@ def apply_pull_actions(
756753

757754
for action in actions:
758755
path = action.pull_delta_item.path
759-
src = self.fpath(path, downloaded_files_directory)
760-
dest = self.fpath(path)
756+
server = self.fpath(path, download_dir)
757+
live = self.fpath(path)
761758
basefile = self.fpath_meta(path)
762759
action_type = action.type
763760
pull_change = action.pull_delta_item.change
764761
local_change = action.local_delta_item.change if action.local_delta_item else None
765762
if action_type == PullActionType.COPY:
766763
# simply copy the file from server
767764
if is_versioned_file(path):
768-
self.geodiff.make_copy_sqlite(src, dest)
769-
self.geodiff.make_copy_sqlite(src, basefile)
765+
self.geodiff.make_copy_sqlite(server, live)
766+
self.geodiff.make_copy_sqlite(server, basefile)
770767
else:
771-
shutil.copy(src, dest)
768+
shutil.copy(server, live)
772769

773770
elif action_type == PullActionType.APPLY_DIFF:
774771
# rebase needed only if both server and local changes are diffs
775772
if pull_change == DeltaChangeType.UPDATE_DIFF and local_change == DeltaChangeType.UPDATE_DIFF:
776-
conflict = self.update_with_rebase(
777-
path, src, dest, basefile, downloaded_files_directory, mc.username()
778-
)
773+
conflict = self.update_with_rebase(path, server, live, basefile, download_dir, mc.username())
779774
if conflict:
780775
conflicts.append(conflict)
781776
else:
782777
# no rebase needed, just apply the diff
783-
self.update_without_rebase(path, src, dest, basefile, downloaded_files_directory)
778+
self.update_without_rebase(path, server, live, basefile, download_dir)
784779

785780
elif action_type == PullActionType.COPY_CONFLICT and not prevent_conflicted_copy(path, mc, server_project):
786781
conflict = self.create_conflicted_copy(path, mc.username())
787782
conflicts.append(conflict)
788783
if self.is_versioned_file(path):
789-
self.geodiff.make_copy_sqlite(src, dest)
790-
self.geodiff.make_copy_sqlite(src, basefile)
784+
self.geodiff.make_copy_sqlite(server, live)
785+
self.geodiff.make_copy_sqlite(server, basefile)
791786
else:
792-
shutil.copy(src, dest)
787+
shutil.copy(server, live)
793788

794789
elif action_type == PullActionType.DELETE:
795790
# remove local file
796-
os.remove(dest)
791+
os.remove(live)
797792
if self.is_versioned_file(path):
798793
os.remove(basefile)
799794

mergin/test/test_client.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,10 @@ def test_create_remote_project_from_local(mc):
280280
project_info = mc.project_info_v2(project_info.get("id"))
281281
assert project_info.version == source_mp.version()
282282
assert project_info.name == test_project
283-
assert project_info.namespace == API_USER
283+
assert project_info.workspace.name == API_USER
284284
assert project_info.id == source_mp.project_id()
285285

286-
version = mc.project_version_info(project_info.get("id"), "v1")
286+
version = mc.project_version_info(project_info.id, "v1")
287287
assert version["name"] == "v1"
288288
assert any(f for f in version["changes"]["added"] if f["path"] == "test.qgs")
289289

@@ -690,7 +690,9 @@ def test_missing_basefile_pull(mc):
690690

691691
# try to sync again -- it should not crash
692692
mc.pull_project(project_dir)
693+
assert os.path.exists(os.path.join(project_dir, ".mergin", "base.gpkg"))
693694
mc.push_project(project_dir)
695+
# check if base file exists again
694696

695697

696698
def test_empty_file_in_subdir(mc):
@@ -3068,7 +3070,7 @@ def test_pull_project(mc: MerginClient, mc2: MerginClient):
30683070
assert mp_to_pull.version() == mp.version()
30693071
assert mp_to_pull.project_id() == mp.project_id()
30703072
assert len(project_info.get("files")) == len(mp.files())
3071-
delta_items = mp.get_pull_delta({"files": mp_to_pull.files(), "version": mp_to_pull.version()})
3072-
for item in [item for item in delta_items if item.change == DeltaChangeType.CREATE]:
3073+
delta = mp.get_pull_delta({"files": mp_to_pull.files(), "version": mp_to_pull.version()})
3074+
for item in [item for item in delta.items if item.change == DeltaChangeType.CREATE]:
30733075
assert os.path.exists(mp_to_pull.fpath(item.path))
30743076
assert os.path.exists(mp_to_pull.fpath_meta("base.gpkg"))

0 commit comments

Comments
 (0)