Exemplo n.º 1
0
def dbsync_status(mc):
    """ Figure out if there are any pending changes in the database or in Mergin """

    _check_has_working_dir()
    _check_has_sync_file()

    # get basic information
    mp = MerginProject(config.project_working_dir)
    if mp.geodiff is None:
        raise DbSyncError(
            "Mergin client installation problem: geodiff not available")
    status_push = mp.get_push_changes()
    if status_push['added'] or status_push['updated'] or status_push['removed']:
        raise DbSyncError(
            "Pending changes in the local directory - that should never happen! "
            + str(status_push))

    project_path = mp.metadata["name"]
    local_version = mp.metadata["version"]
    print("Working directory " + config.project_working_dir)
    print("Mergin project " + project_path + " at local version " +
          local_version)
    print("")
    print("Checking status...")

    # check if there are any pending changes on server
    try:
        server_info = mc.project_info(project_path, since=local_version)
    except ClientError as e:
        raise DbSyncError("Mergin client error: " + str(e))

    print("Server is at version " + server_info["version"])

    status_pull = mp.get_pull_changes(server_info["files"])
    if status_pull['added'] or status_pull['updated'] or status_pull['removed']:
        print("There are pending changes on server:")
        _print_mergin_changes(status_pull)
    else:
        print("No pending changes on server.")

    print("")
    conn = psycopg2.connect(config.db_conn_info)

    if not _check_schema_exists(conn, config.db_schema_base):
        raise DbSyncError("The base schema does not exist: " +
                          config.db_schema_base)
    if not _check_schema_exists(conn, config.db_schema_modified):
        raise DbSyncError("The 'modified' schema does not exist: " +
                          config.db_schema_modified)

    # get changes in the DB
    tmp_dir = tempfile.gettempdir()
    tmp_changeset_file = os.path.join(tmp_dir, 'dbsync-status-base2our')
    if os.path.exists(tmp_changeset_file):
        os.remove(tmp_changeset_file)
    _geodiff_create_changeset(config.db_driver, config.db_conn_info,
                              config.db_schema_base, config.db_schema_modified,
                              tmp_changeset_file)

    if os.path.getsize(tmp_changeset_file) == 0:
        print("No changes in the database.")
    else:
        print("There are changes in DB")
        # summarize changes
        summary = _geodiff_list_changes_summary(tmp_changeset_file)
        _print_changes_summary(summary)
Exemplo n.º 2
0
def dbsync_push(mc):
    """ Take changes in the 'modified' schema in the database and push them to Mergin """

    tmp_dir = tempfile.gettempdir()
    tmp_changeset_file = os.path.join(tmp_dir, 'dbsync-push-base2our')
    if os.path.exists(tmp_changeset_file):
        os.remove(tmp_changeset_file)

    _check_has_working_dir()
    _check_has_sync_file()

    mp = MerginProject(config.project_working_dir)
    if mp.geodiff is None:
        raise DbSyncError(
            "Mergin client installation problem: geodiff not available")
    project_path = mp.metadata["name"]
    local_version = mp.metadata["version"]

    try:
        projects = mc.get_projects_by_names([project_path])
        server_version = projects[project_path]["version"]
    except ClientError as e:
        # this could be e.g. DNS error
        raise DbSyncError("Mergin client error: " + str(e))

    status_push = mp.get_push_changes()
    if status_push['added'] or status_push['updated'] or status_push['removed']:
        raise DbSyncError(
            "There are pending changes in the local directory - that should never happen! "
            + str(status_push))

    # check there are no pending changes on server
    if server_version != local_version:
        raise DbSyncError(
            "There are pending changes on server - need to pull them first.")

    conn = psycopg2.connect(config.db_conn_info)

    if not _check_schema_exists(conn, config.db_schema_base):
        raise DbSyncError("The base schema does not exist: " +
                          config.db_schema_base)
    if not _check_schema_exists(conn, config.db_schema_modified):
        raise DbSyncError("The 'modified' schema does not exist: " +
                          config.db_schema_modified)

    # get changes in the DB
    _geodiff_create_changeset(config.db_driver, config.db_conn_info,
                              config.db_schema_base, config.db_schema_modified,
                              tmp_changeset_file)

    if os.path.getsize(tmp_changeset_file) == 0:
        print("No changes in the database.")
        return

    # summarize changes
    summary = _geodiff_list_changes_summary(tmp_changeset_file)
    _print_changes_summary(summary)

    # write changes to the local geopackage
    print("Writing DB changes to working dir...")
    gpkg_full_path = os.path.join(config.project_working_dir,
                                  config.mergin_sync_file)
    _geodiff_apply_changeset("sqlite", "", gpkg_full_path, tmp_changeset_file)

    # write to the server
    try:
        mc.push_project(config.project_working_dir)
    except ClientError as e:
        # TODO: should we do some cleanup here? (undo changes in the local geopackage?)
        raise DbSyncError("Mergin client error on push: " + str(e))

    version = _get_project_version()
    print("Pushed new version to Mergin: " + version)

    # update base schema in the DB
    print("Updating DB base schema...")
    _geodiff_apply_changeset(config.db_driver, config.db_conn_info,
                             config.db_schema_base, tmp_changeset_file)
    _set_db_project_comment(conn, config.db_schema_base,
                            config.mergin_project_name, version)

    print("Push done!")
Exemplo n.º 3
0
def dbsync_pull(mc):
    """ Downloads any changes from Mergin and applies them to the database """

    _check_has_working_dir()
    _check_has_sync_file()

    mp = MerginProject(config.project_working_dir)
    if mp.geodiff is None:
        raise DbSyncError(
            "Mergin client installation problem: geodiff not available")
    project_path = mp.metadata["name"]
    local_version = mp.metadata["version"]

    try:
        projects = mc.get_projects_by_names([project_path])
        server_version = projects[project_path]["version"]
    except ClientError as e:
        # this could be e.g. DNS error
        raise DbSyncError("Mergin client error: " + str(e))

    status_push = mp.get_push_changes()
    if status_push['added'] or status_push['updated'] or status_push['removed']:
        raise DbSyncError(
            "There are pending changes in the local directory - that should never happen! "
            + str(status_push))

    if server_version == local_version:
        print("No changes on Mergin.")
        return

    gpkg_basefile = os.path.join(config.project_working_dir, '.mergin',
                                 config.mergin_sync_file)
    gpkg_basefile_old = gpkg_basefile + "-old"

    # make a copy of the basefile in the current version (base) - because after pull it will be set to "their"
    shutil.copy(gpkg_basefile, gpkg_basefile_old)

    tmp_dir = tempfile.gettempdir()
    tmp_base2our = os.path.join(tmp_dir, 'dbsync-pull-base2our')
    tmp_base2their = os.path.join(tmp_dir, 'dbsync-pull-base2their')

    # find out our local changes in the database (base2our)
    _geodiff_create_changeset(config.db_driver, config.db_conn_info,
                              config.db_schema_base, config.db_schema_modified,
                              tmp_base2our)

    needs_rebase = False
    if os.path.getsize(tmp_base2our) != 0:
        needs_rebase = True
        summary = _geodiff_list_changes_summary(tmp_base2our)
        _print_changes_summary(summary, "DB Changes:")

    try:
        mc.pull_project(config.project_working_dir)  # will do rebase as needed
    except ClientError as e:
        # TODO: do we need some cleanup here?
        raise DbSyncError("Mergin client error on pull: " + str(e))

    print("Pulled new version from Mergin: " + _get_project_version())

    # simple case when there are no pending local changes - just apply whatever changes are coming
    _geodiff_create_changeset("sqlite", "", gpkg_basefile_old, gpkg_basefile,
                              tmp_base2their)

    # summarize changes
    summary = _geodiff_list_changes_summary(tmp_base2their)
    _print_changes_summary(summary, "Mergin Changes:")

    if not needs_rebase:
        print("Applying new version [no rebase]")
        _geodiff_apply_changeset(config.db_driver, config.db_conn_info,
                                 config.db_schema_base, tmp_base2their)
        _geodiff_apply_changeset(config.db_driver, config.db_conn_info,
                                 config.db_schema_modified, tmp_base2their)
    else:
        print("Applying new version [WITH rebase]")
        tmp_conflicts = os.path.join(tmp_dir, 'dbsync-pull-conflicts')
        _geodiff_rebase(config.db_driver, config.db_conn_info,
                        config.db_schema_base, config.db_schema_modified,
                        tmp_base2their, tmp_conflicts)
        _geodiff_apply_changeset(config.db_driver, config.db_conn_info,
                                 config.db_schema_base, tmp_base2their)

    os.remove(gpkg_basefile_old)
    conn = psycopg2.connect(config.db_conn_info)
    version = _get_project_version()
    _set_db_project_comment(conn, config.db_schema_base,
                            config.mergin_project_name, version)
    print("Pull done!")