Skip to content

Commit 07a8d9c

Browse files
alexbruywonder-sk
authored andcommitted
move geodiff-related code from apply_pull_changes to new methods which
update versioned file with or without rebase (fix #116)
1 parent f4abbc8 commit 07a8d9c

File tree

1 file changed

+105
-55
lines changed

1 file changed

+105
-55
lines changed

mergin/merginproject.py

Lines changed: 105 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -410,65 +410,13 @@ def apply_pull_changes(self, changes, temp_dir):
410410
# 'src' here is server version of file and 'dest' is locally modified
411411
if self.is_versioned_file(path) and k == 'updated':
412412
if path in modified:
413-
self.log.info("updating file with rebase: " + path)
414-
server_diff = self.fpath(f'{path}-server_diff', temp_dir) # diff between server file and local basefile
415-
local_diff = self.fpath(f'{path}-local_diff', temp_dir)
416-
417-
# temporary backup of file pulled from server for recovery
418-
f_server_backup = self.fpath(f'{path}-server_backup', temp_dir)
419-
self.geodiff.make_copy_sqlite(src, f_server_backup)
420-
421-
# create temp backup (ideally with geodiff) of locally modified file if needed later
422-
f_conflict_file = self.fpath(f'{path}-local_backup', temp_dir)
423-
try:
424-
self.geodiff.create_changeset(basefile, dest, local_diff)
425-
self.geodiff.make_copy_sqlite(basefile, f_conflict_file)
426-
self.geodiff.apply_changeset(f_conflict_file, local_diff)
427-
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError):
428-
self.log.info("backup of local file with geodiff failed - need to do hard copy")
429-
self.geodiff.make_copy_sqlite(dest, f_conflict_file)
430-
431-
# in case there will be any conflicting operations found during rebase,
432-
# they will be stored in a JSON file - if there are no conflicts, the file
433-
# won't even be created
434-
rebase_conflicts = self.fpath(f'{path}_rebase_conflicts')
435-
436-
# try to do rebase magic
437-
try:
438-
self.geodiff.create_changeset(basefile, src, server_diff)
439-
self.geodiff.rebase(basefile, src, dest, rebase_conflicts)
440-
# make sure basefile is in the same state as remote server file (for calc of push changes)
441-
self.geodiff.apply_changeset(basefile, server_diff)
442-
self.log.info("rebase successful!")
443-
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError) as err:
444-
self.log.warning("rebase failed! going to create conflict file")
445-
# it would not be possible to commit local changes, they need to end up in new conflict file
446-
self.geodiff.make_copy_sqlite(f_conflict_file, dest)
447-
conflict = self.backup_file(path)
413+
conflict = self.update_with_rebase(path, src, dest, basefile, temp_dir)
414+
if conflict:
448415
conflicts.append(conflict)
449-
# original file synced with server
450-
self.geodiff.make_copy_sqlite(f_server_backup, basefile)
451-
self.geodiff.make_copy_sqlite(f_server_backup, dest)
452416
else:
453417
# The local file is not modified -> no rebase needed.
454418
# We just apply the diff between our copy and server to both the local copy and its basefile
455-
self.log.info("updating file without rebase: " + path)
456-
try:
457-
server_diff = self.fpath(f'{path}-server_diff', temp_dir) # diff between server file and local basefile
458-
# TODO: it could happen that basefile does not exist.
459-
# It was either never created (e.g. when pushing without geodiff)
460-
# or it was deleted by mistake(?) by the user. We should detect that
461-
# when starting pull and download it as well
462-
self.geodiff.create_changeset(basefile, src, server_diff)
463-
self.geodiff.apply_changeset(dest, server_diff)
464-
self.geodiff.apply_changeset(basefile, server_diff)
465-
self.log.info("update successful")
466-
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError):
467-
self.log.warning("update failed! going to copy file")
468-
# something bad happened and we have failed to patch our local files - this should not happen if there
469-
# wasn't a schema change or something similar that geodiff can't handle.
470-
self.geodiff.make_copy_sqlite(src, dest)
471-
self.geodiff.make_copy_sqlite(src, basefile)
419+
self.update_without_rebase(path, src, dest, basefile, temp_dir)
472420
else:
473421
# backup if needed
474422
if path in modified and item['checksum'] != local_files_map[path]['checksum']:
@@ -492,6 +440,108 @@ def apply_pull_changes(self, changes, temp_dir):
492440

493441
return conflicts
494442

443+
def update_with_rebase(self, path, src, dest, basefile, temp_dir):
444+
"""
445+
Update a versioned file with rebase.
446+
447+
Try to peform automatic rebase, create conflict file if failed.pyt
448+
449+
.. seealso:: self.update_without_rebase
450+
451+
:param path: path to geodiff file
452+
:type path: str
453+
:param src: path to the server version of the file
454+
:type src: str
455+
:param dest: path to the local version of the file
456+
:type dest: str
457+
:param basefile: path to a file in meta dir
458+
:type basefile: str
459+
:param temp_dir: directory with downloaded files from server
460+
:type temp_dir: str
461+
:returns: path to conflict file if rebase fails, empty string on success
462+
:rtype: str
463+
"""
464+
self.log.info("updating file with rebase: " + path)
465+
466+
server_diff = self.fpath(f'{path}-server_diff', temp_dir) # diff between server file and local basefile
467+
local_diff = self.fpath(f'{path}-local_diff', temp_dir)
468+
469+
# temporary backup of file pulled from server for recovery
470+
f_server_backup = self.fpath(f'{path}-server_backup', temp_dir)
471+
self.geodiff.make_copy_sqlite(src, f_server_backup)
472+
473+
# create temp backup (ideally with geodiff) of locally modified file if needed later
474+
f_conflict_file = self.fpath(f'{path}-local_backup', temp_dir)
475+
try:
476+
self.geodiff.create_changeset(basefile, dest, local_diff)
477+
self.geodiff.make_copy_sqlite(basefile, f_conflict_file)
478+
self.geodiff.apply_changeset(f_conflict_file, local_diff)
479+
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError):
480+
self.log.info("backup of local file with geodiff failed - need to do hard copy")
481+
self.geodiff.make_copy_sqlite(dest, f_conflict_file)
482+
483+
# in case there will be any conflicting operations found during rebase,
484+
# they will be stored in a JSON file - if there are no conflicts, the file
485+
# won't even be created
486+
rebase_conflicts = self.fpath(f'{path}_rebase_conflicts')
487+
488+
# try to do rebase magic
489+
try:
490+
self.geodiff.create_changeset(basefile, src, server_diff)
491+
self.geodiff.rebase(basefile, src, dest, rebase_conflicts)
492+
# make sure basefile is in the same state as remote server file (for calc of push changes)
493+
self.geodiff.apply_changeset(basefile, server_diff)
494+
self.log.info("rebase successful!")
495+
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError) as err:
496+
self.log.warning("rebase failed! going to create conflict file")
497+
# it would not be possible to commit local changes, they need to end up in new conflict file
498+
self.geodiff.make_copy_sqlite(f_conflict_file, dest)
499+
conflict = self.backup_file(path)
500+
# original file synced with server
501+
self.geodiff.make_copy_sqlite(f_server_backup, basefile)
502+
self.geodiff.make_copy_sqlite(f_server_backup, dest)
503+
return conflict
504+
505+
return ''
506+
507+
def update_without_rebase(self, path, src, dest, basefile, temp_dir):
508+
"""
509+
Update a versioned file without rebase.
510+
511+
Apply the diff between local copy and server to both the local
512+
copy and its basefile.
513+
514+
.. seealso:: self.update_with_rebase
515+
516+
:param path: path to geodiff file
517+
:type path: str
518+
:param src: path to the server version of the file
519+
:type src: str
520+
:param dest: path to the local version of the file
521+
:type dest: str
522+
:param basefile: path to a file in meta dir
523+
:type basefile: str
524+
:param temp_dir: directory with downloaded files from server
525+
:type temp_dir: str
526+
"""
527+
self.log.info("updating file without rebase: " + path)
528+
try:
529+
server_diff = self.fpath(f'{path}-server_diff', temp_dir) # diff between server file and local basefile
530+
# TODO: it could happen that basefile does not exist.
531+
# It was either never created (e.g. when pushing without geodiff)
532+
# or it was deleted by mistake(?) by the user. We should detect that
533+
# when starting pull and download it as well
534+
self.geodiff.create_changeset(basefile, src, server_diff)
535+
self.geodiff.apply_changeset(dest, server_diff)
536+
self.geodiff.apply_changeset(basefile, server_diff)
537+
self.log.info("update successful")
538+
except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError):
539+
self.log.warning("update failed! going to copy file")
540+
# something bad happened and we have failed to patch our local files - this should not happen if there
541+
# wasn't a schema change or something similar that geodiff can't handle.
542+
self.geodiff.make_copy_sqlite(src, dest)
543+
self.geodiff.make_copy_sqlite(src, basefile)
544+
495545
def apply_push_changes(self, changes):
496546
"""
497547
For geodiff files update basefiles according to changes pushed to server.

0 commit comments

Comments
 (0)