mergin/client_pull.py
def pull_project_finalize(job):
    """
    To be called when pull in the background is finished and we need to do the finalization (merge chunks etc.)

    This should not be called from a worker thread (e.g. directly from a handler when download is complete)

    If any of the workers has thrown any exception, it will be re-raised (e.g. some network errors).
    That also means that the whole job has been aborted.
    """

    job.executor.shutdown(wait=True)

    # make sure any exceptions from threads are not lost
    for future in job.futures:
        if future.exception() is not None:
            job.mp.log.error("Error while pulling data: " + str(future.exception()))
            job.mp.log.info("--- pull aborted")
            raise future.exception()

    job.mp.log.info("finalizing pull")

    # merge downloaded chunks
    try:
        for file_to_merge in job.files_to_merge:
            file_to_merge.merge()
    except ClientError as err:
        job.mp.log.error("Error merging chunks of downloaded file: " + str(err))
        job.mp.log.info("--- pull aborted")
        raise

    # make sure we can update geodiff reference files (aka. basefiles) with diffs or
    # download their full versions so we have them up-to-date for applying changes
    for file_path, file_diffs in job.basefiles_to_patch:
        basefile = job.mp.fpath_meta(file_path)
        server_file = job.mp.fpath(file_path, job.temp_dir)

        shutil.copy(basefile, server_file)
        diffs = [job.mp.fpath(f, job.temp_dir) for f in file_diffs]
        patch_error = job.mp.apply_diffs(server_file, diffs)
        if patch_error:
            # that's weird that we are unable to apply diffs to the basefile!
            # because it should be possible to apply them cleanly since the server
            # was also able to apply those diffs. It could be that someone modified
            # the basefile and we ended up in this inconsistent state.
            # let's remove the basefile and let the user retry - we should download clean version again
            job.mp.log.error(f"Error patching basefile {basefile}")
            job.mp.log.error("Diffs we were applying: " + str(diffs))
            job.mp.log.error("Removing basefile because it would be corrupted anyway...")
            job.mp.log.info("--- pull aborted")
            os.remove(basefile)
            raise ClientError("Cannot patch basefile {}! Please try syncing again.".format(basefile))

    try:
        conflicts = job.mp.apply_pull_changes(job.pull_changes, job.temp_dir, job.user_name)
    except Exception as e:
        job.mp.log.error("Failed to apply pull changes: " + str(e))
        job.mp.log.info("--- pull aborted")
        raise ClientError("Failed to apply pull changes: " + str(e))

    job.mp.metadata = {
        'name': job.project_path,
        'version': job.version if job.version else "v0",  # for new projects server version is ""
        'files': job.project_info['files']
    }

    if job.mp.has_unfinished_pull():
        job.mp.log.info("--- failed to complete pull -- project left in the unfinished pull state")
    else:
        job.mp.log.info("--- pull finished -- at version " + job.mp.metadata['version'])

    shutil.rmtree(job.temp_dir)
    return conflicts

    To be called when pull in the background is finished and we need to do the finalization (merge chunks etc.)

    This should not be called from a worker thread (e.g. directly from a handler when download is complete)

    If any of the workers has thrown any exception, it will be re-raised (e.g. some network errors).
    That also means that the whole job has been aborted.
    
To be called when pull in the background is finished and we need to do the finalization (merge chunks etc.)
This should not be called from a worker thread

If any of the workers has thrown any exception, it will be re-raised .
That also means that the whole job has been aborted.
To be called when pull in the background is finished and we need to do the finalization ( merge chunks etc . ) This should not be called from a worker thread If any of the workers has thrown any exception it will be re - raised . That also means that the whole job has been aborted .
def pull_project_finalize(job):
    job.executor.shutdown(wait=True)
    for future in job.futures:
        if future.exception() is not None:
            job.mp.log.error("Error while pulling data: " + str(future.exception()))
            job.mp.log.info("--- pull aborted")
            raise future.exception()
    job.mp.log.info("finalizing pull")
    try:
        for file_to_merge in job.files_to_merge:
            file_to_merge.merge()
    except ClientError as err:
        job.mp.log.error("Error merging chunks of downloaded file: " + str(err))
        job.mp.log.info("--- pull aborted")
        raise
    for file_path, file_diffs in job.basefiles_to_patch:
        basefile = job.mp.fpath_meta(file_path)
        server_file = job.mp.fpath(file_path, job.temp_dir)
        shutil.copy(basefile, server_file)
        diffs = [job.mp.fpath(f, job.temp_dir) for f in file_diffs]
        patch_error = job.mp.apply_diffs(server_file, diffs)
        if patch_error:
            job.mp.log.error(f"Error patching basefile {basefile}")
            job.mp.log.error("Diffs we were applying: " + str(diffs))
            job.mp.log.error("Removing basefile because it would be corrupted anyway...")
            job.mp.log.info("--- pull aborted")
            os.remove(basefile)
            raise ClientError("Cannot patch basefile {}! Please try syncing again.".format(basefile))
    try:
        conflicts = job.mp.apply_pull_changes(job.pull_changes, job.temp_dir, job.user_name)
    except Exception as e:
        job.mp.log.error("Failed to apply pull changes: " + str(e))
        job.mp.log.info("--- pull aborted")
        raise ClientError("Failed to apply pull changes: " + str(e))
    job.mp.metadata = {
        'name': job.project_path,
        'version': job.version if job.version else "v0",  
        'files': job.project_info['files']
    }
    if job.mp.has_unfinished_pull():
        job.mp.log.info("--- failed to complete pull -- project left in the unfinished pull state")
    else:
        job.mp.log.info("--- pull finished -- at version " + job.mp.metadata['version'])
    shutil.rmtree(job.temp_dir)
    return conflicts
def pull_project_finalize ( job ) : job . executor . shutdown ( wait = True ) for future in job . futures : if future . exception ( ) is not None : job . mp . log . error ( "Error while pulling data: " + str ( future . exception ( ) ) ) job . mp . log . info ( "--- pull aborted" ) raise future . exception ( ) job . mp . log . info ( "finalizing pull" ) try : for file_to_merge in job . files_to_merge : file_to_merge . merge ( ) except ClientError as err : job . mp . log . error ( "Error merging chunks of downloaded file: " + str ( err ) ) job . mp . log . info ( "--- pull aborted" ) raise for file_path , file_diffs in job . basefiles_to_patch : basefile = job . mp . fpath_meta ( file_path ) server_file = job . mp . fpath ( file_path , job . temp_dir ) shutil . copy ( basefile , server_file ) diffs = [ job . mp . fpath ( f , job . temp_dir ) for f in file_diffs ] patch_error = job . mp . apply_diffs ( server_file , diffs ) if patch_error : job . mp . log . error ( f"Error patching basefile {basefile}" ) job . mp . log . error ( "Diffs we were applying: " + str ( diffs ) ) job . mp . log . error ( "Removing basefile because it would be corrupted anyway..." ) job . mp . log . info ( "--- pull aborted" ) os . remove ( basefile ) raise ClientError ( "Cannot patch basefile {}! Please try syncing again." . format ( basefile ) ) try : conflicts = job . mp . apply_pull_changes ( job . pull_changes , job . temp_dir , job . user_name ) except Exception as e : job . mp . log . error ( "Failed to apply pull changes: " + str ( e ) ) job . mp . log . info ( "--- pull aborted" ) raise ClientError ( "Failed to apply pull changes: " + str ( e ) ) job . mp . metadata = { 'name' : job . project_path , 'version' : job . version if job . version else "v0" , 'files' : job . project_info [ 'files' ] } if job . mp . has_unfinished_pull ( ) : job . mp . log . info ( "--- failed to complete pull -- project left in the unfinished pull state" ) else : job . mp . log . info ( "--- pull finished -- at version " + job . mp . metadata [ 'version' ] ) shutil . rmtree ( job . temp_dir ) return conflicts
To be called when pull in the background is finished and we need to do the finalization (merge chunks etc.)
To be called when pull in the background is finished and we need to do the finalization ( merge chunks etc . )
"""
    To be called when pull in the background is finished and we need to do the finalization (merge chunks etc.)

    This should not be called from a worker thread (e.g. directly from a handler when download is complete)

    If any of the workers has thrown any exception, it will be re-raised (e.g. some network errors).
    That also means that the whole job has been aborted.
    """ # make sure any exceptions from threads are not lost # merge downloaded chunks # make sure we can update geodiff reference files (aka. basefiles) with diffs or # download their full versions so we have them up-to-date for applying changes # that's weird that we are unable to apply diffs to the basefile! # because it should be possible to apply them cleanly since the server # was also able to apply those diffs. It could be that someone modified # the basefile and we ended up in this inconsistent state. # let's remove the basefile and let the user retry - we should download clean version again # for new projects server version is ""
job