1515import sys
1616import tempfile
1717import random
18+ import uuid
1819
1920import psycopg2
2021from itertools import chain
@@ -199,14 +200,25 @@ def _get_project_version(work_path):
199200 return mp .metadata ["version" ]
200201
201202
202- def _set_db_project_comment (conn , schema , project_name , version , error = None ):
203+ def _get_project_id (mp ):
204+ """ Returns the project ID """
205+ try :
206+ project_id = uuid .UUID (mp .metadata ["project_id" ])
207+ except (KeyError , ValueError ):
208+ project_id = None
209+ return project_id
210+
211+
212+ def _set_db_project_comment (conn , schema , project_name , version , project_id = None , error = None ):
203213 """ Set postgres COMMENT on SCHEMA with Mergin Maps project name and version
204214 or eventually error message if initialisation failed
205215 """
206216 comment = {
207217 "name" : project_name ,
208218 "version" : version ,
209219 }
220+ if project_id :
221+ comment ["project_id" ] = project_id
210222 if error :
211223 comment ["error" ] = error
212224 cur = conn .cursor ()
@@ -238,6 +250,25 @@ def _redownload_project(conn_cfg, mc, work_dir, db_proj_info):
238250 raise DbSyncError ("Mergin Maps client error: " + str (e ))
239251
240252
253+ def _validate_local_project_id (mp , mc , server_info = None ):
254+ """Compare local project ID with remote version on the server."""
255+ local_project_id = _get_project_id (mp )
256+ if local_project_id is None :
257+ return
258+ project_path = mp .metadata ["name" ]
259+ if server_info is None :
260+ try :
261+ server_info = mc .project_info (project_path )
262+ except ClientError as e :
263+ raise DbSyncError ("Mergin Maps client error: " + str (e ))
264+
265+ remote_project_id = uuid .UUID (server_info ["id" ])
266+ if local_project_id != remote_project_id :
267+ raise DbSyncError (
268+ f"The local project ID ({ local_project_id } ) does not match the server project ID ({ remote_project_id } )"
269+ )
270+
271+
241272def create_mergin_client ():
242273 """ Create instance of MerginClient"""
243274 _check_has_password ()
@@ -301,6 +332,10 @@ def pull(conn_cfg, mc):
301332 mp .set_tables_to_skip (ignored_tables )
302333 if mp .geodiff is None :
303334 raise DbSyncError ("Mergin Maps client installation problem: geodiff not available" )
335+
336+ # Make sure that local project ID (if available) is the same as on the server
337+ _validate_local_project_id (mp , mc )
338+
304339 project_path = mp .metadata ["name" ]
305340 local_version = mp .metadata ["version" ]
306341
@@ -390,25 +425,26 @@ def status(conn_cfg, mc):
390425 mp .set_tables_to_skip (ignored_tables )
391426 if mp .geodiff is None :
392427 raise DbSyncError ("Mergin Maps client installation problem: geodiff not available" )
393- status_push = mp .get_push_changes ()
394- if status_push ['added' ] or status_push ['updated' ] or status_push ['removed' ]:
395- raise DbSyncError ("Pending changes in the local directory - that should never happen! " + str (status_push ))
396-
397428 project_path = mp .metadata ["name" ]
398429 local_version = mp .metadata ["version" ]
399- print ("Working directory " + work_dir )
400- print ("Mergin Maps project " + project_path + " at local version " + local_version )
401- print ("" )
402430 print ("Checking status..." )
403-
404- # check if there are any pending changes on server
405431 try :
406432 server_info = mc .project_info (project_path , since = local_version )
407433 except ClientError as e :
408434 raise DbSyncError ("Mergin Maps client error: " + str (e ))
409435
410- print ("Server is at version " + server_info ["version" ])
436+ # Make sure that local project ID (if available) is the same as on the server
437+ _validate_local_project_id (mp , mc , server_info )
438+
439+ status_push = mp .get_push_changes ()
440+ if status_push ['added' ] or status_push ['updated' ] or status_push ['removed' ]:
441+ raise DbSyncError ("Pending changes in the local directory - that should never happen! " + str (status_push ))
411442
443+ print ("Working directory " + work_dir )
444+ print ("Mergin Maps project " + project_path + " at local version " + local_version )
445+ print ("" )
446+
447+ print ("Server is at version " + server_info ["version" ])
412448 status_pull = mp .get_pull_changes (server_info ["files" ])
413449 if status_pull ['added' ] or status_pull ['updated' ] or status_pull ['removed' ]:
414450 print ("There are pending changes on server:" )
@@ -462,6 +498,10 @@ def push(conn_cfg, mc):
462498 mp .set_tables_to_skip (ignored_tables )
463499 if mp .geodiff is None :
464500 raise DbSyncError ("Mergin Maps client installation problem: geodiff not available" )
501+
502+ # Make sure that local project ID (if available) is the same as on the server
503+ _validate_local_project_id (mp , mc )
504+
465505 project_path = mp .metadata ["name" ]
466506 local_version = mp .metadata ["version" ]
467507
@@ -560,9 +600,17 @@ def init(conn_cfg, mc, from_gpkg=True):
560600 f"to { work_dir } " )
561601 mc .download_project (conn_cfg .mergin_project , work_dir , db_proj_info ["version" ])
562602 else :
603+ # Get project ID from DB if available
563604 try :
564605 local_version = _get_project_version (work_dir )
565606 print (f"Working directory { work_dir } already exists, with project version { local_version } " )
607+ # Compare local and database project version
608+ db_project_id_str = getattr (db_proj_info , "project_id" , None )
609+ db_project_id = uuid .UUID (db_project_id_str ) if db_project_id_str else None
610+ mp = _get_mergin_project (work_dir )
611+ local_project_id = _get_project_id (mp )
612+ if (db_project_id and local_project_id ) and (db_project_id != local_project_id ):
613+ raise DbSyncError (f"Database project ID doesn't match local project ID." )
566614 if local_version != db_proj_info ["version" ]:
567615 _redownload_project (conn_cfg , mc , work_dir , db_proj_info )
568616 except InvalidProject as e :
@@ -579,6 +627,9 @@ def init(conn_cfg, mc, from_gpkg=True):
579627 # make sure we have working directory now
580628 _check_has_working_dir (work_dir )
581629 local_version = _get_project_version (work_dir )
630+ mp = _get_mergin_project (work_dir )
631+ # Make sure that local project ID (if available) is the same as on the server
632+ _validate_local_project_id (mp , mc )
582633
583634 # check there are no pending changes on server (or locally - which should never happen)
584635 status_pull , status_push , _ = mc .project_status (work_dir )
0 commit comments