@@ -365,25 +365,31 @@ def apply_pull_changes(self, changes, temp_dir):
365365 # special care is needed for geodiff files
366366 if self .is_versioned_file (path ) and k == 'updated' :
367367 if path in modified :
368+ f_server_backup = self .fpath (f'{ path } -server_backup' , temp_dir )
368369 server_diff = self .fpath (f'{ path } -server_diff' , temp_dir ) # single origin diff from 'diffs' for use in rebase
369370 rebased_diff = self .fpath (f'{ path } -rebased' , temp_dir )
370- patchedfile = self .fpath (f'{ path } -patched' , temp_dir ) # patched server version with local changes
371- changeset = self .fpath (f'{ path } -local_diff' , temp_dir ) # final changeset to be potentially committed
371+ shutil .copy (src , f_server_backup ) # temporary backup of file pulled from server for test and recovery
372372 try :
373373 self .geodiff .create_changeset (basefile , src , server_diff )
374374 self .geodiff .create_rebased_changeset (basefile , dest , server_diff , rebased_diff )
375- self .geodiff .apply_changeset (src , patchedfile , rebased_diff )
376- self .geodiff .create_changeset (src , patchedfile , changeset )
377- shutil .copy (src , basefile )
378- shutil .copy (patchedfile , dest )
375+ # update file with rebased_diff to contain both server and local changes
376+ self .geodiff .apply_changeset (src , rebased_diff )
377+ # try to create final changeset to be potentially committed in push
378+ changeset = self .fpath (f'{ path } -local_diff' , temp_dir )
379+ self .geodiff .create_changeset (f_server_backup , src , changeset )
380+ # we are happy with rebase, prepare 'live' versions of files
381+ shutil .copy (f_server_backup , basefile )
382+ shutil .copy (src , dest )
379383 except (pygeodiff .GeoDiffLibError , pygeodiff .GeoDiffLibConflictError ):
380- # it would not be possible to commit local changes, create new conflict file instead
384+ # it would not be possible to commit local changes
385+ # local changes will end up in new conflict file
386+ # for original file server wins
381387 conflict = self .backup_file (path )
382388 conflicts .append (conflict )
383- shutil .copy (src , dest )
384- shutil .copy (src , basefile )
389+ shutil .copy (f_server_backup , dest )
390+ shutil .copy (f_server_backup , basefile )
385391 else :
386- # just use already updated tmp_basefile to update project file and its basefile
392+ # just use server version of file to update both project file and its basefile
387393 shutil .copy (src , dest )
388394 shutil .copy (src , basefile )
389395 else :
@@ -432,10 +438,8 @@ def apply_push_changes(self, changes):
432438 elif k == 'updated' :
433439 # better to apply diff to previous basefile to avoid issues with geodiff tmp files
434440 changeset = self .fpath_meta (item ['diff' ]['path' ])
435- patchedfile = self .apply_diffs (basefile , [changeset ])
436- if patchedfile :
437- move_file (patchedfile , basefile )
438- else :
441+ patch_error = self .apply_diffs (basefile , [changeset ])
442+ if patch_error :
439443 # in case of local sync issues it is safier to remove basefile, next time it will be downloaded from server
440444 os .remove (basefile )
441445 else :
@@ -464,29 +468,26 @@ def backup_file(self, file):
464468 def apply_diffs (self , basefile , diffs ):
465469 """
466470 Helper function to update content of geodiff file using list of diffs.
471+ Input file will be overwritten (make sure to create backup if needed).
467472
468473 :param basefile: abs path to file to be updated
469474 :type basefile: str
470475 :param diffs: list of abs paths to geodiff changeset files
471476 :type diffs: list[str]
472- :returns: abs path of created patched file
477+ :returns: error message if diffs were not successfully applied or None
473478 :rtype: str
474479 """
480+ error = None
475481 if not self .is_versioned_file (basefile ):
476- return
482+ return error
477483
478- patchedfile = None
479484 for index , diff in enumerate (diffs ):
480- patchedfile = f'{ basefile } -patched-{ index } '
481485 try :
482- self .geodiff .apply_changeset (basefile , patchedfile , diff )
483- except (pygeodiff .GeoDiffLibError , pygeodiff .GeoDiffLibConflictError ):
484- return
485- previous = f'{ basefile } -patched-{ index - 1 } '
486- if os .path .exists (previous ):
487- os .remove (previous )
488- basefile = patchedfile
489- return patchedfile
486+ self .geodiff .apply_changeset (basefile , diff )
487+ except (pygeodiff .GeoDiffLibError , pygeodiff .GeoDiffLibConflictError ) as e :
488+ error = str (e )
489+ break
490+ return error
490491
491492
492493def decode_token_data (token ):
@@ -924,16 +925,17 @@ def pull_project(self, directory, parallel=True):
924925 continue
925926 file ['version' ] = server_info ['version' ]
926927 basefile = mp .fpath_meta (file ['path' ])
927- if not os .path .exists (basefile ):
928- self ._download_file (project_path , file , temp_dir , parallel , diff_only = False )
929-
930- diffs = [mp .fpath (f , temp_dir ) for f in file ['diffs' ]]
931- patched_reference = mp .apply_diffs (basefile , diffs )
932- if not patched_reference :
928+ server_file = mp .fpath (file ["path" ], temp_dir )
929+ if os .path .exists (basefile ):
930+ shutil .copy (basefile , server_file )
931+ diffs = [mp .fpath (f , temp_dir ) for f in file ['diffs' ]]
932+ patch_error = mp .apply_diffs (server_file , diffs )
933+ if patch_error :
934+ # we can't use diffs, overwrite with full version of file fetched from server
935+ self ._download_file (project_path , file , temp_dir , parallel , diff_only = False )
936+ else :
933937 self ._download_file (project_path , file , temp_dir , parallel , diff_only = False )
934938
935- move_file (patched_reference , mp .fpath (file ["path" ], temp_dir ))
936-
937939 conflicts = mp .apply_pull_changes (pull_changes , temp_dir )
938940 mp .metadata = {
939941 'name' : project_path ,
0 commit comments