Skip to content

How to install QField Cloud Sync

Manual build

To manually install and build the required libraries follow these steps:

  1. Install Python 3 dependencies and build tools:

        apt-get install python3 python3-pip python3-virtualenv libpq-dev \
                python3-setuptools iputils-ping python3-psycopg2 git \
            gcc build-essential binutils cmake extra-cmake-modules \
                libsqlite3-mod-spatialite libsqlite3-dev python3-numpy
    

  2. Create a virtual environment and install QField Cloud CLI

        virtualenv --python=/usr/bin/python3 --system-site-packages .venv
        source .venv/bin/activate
        pip3 install qfieldcloud-sdk
    

  3. Compile geodiff with PostgreSQL support:

git clone --branch 2.0.2 https://github.com/MerginMaps/geodiff.git
cd geodiff

  # fix for geodiff copy issue
  sed -i.save '160isql += "CREATE EXTENSION IF NOT EXISTS POSTGIS;";' geodiff/src/drivers/postgresdriver.cpp

mkdir build && cd build
cmake -DWITH_POSTGRESQL=TRUE -DENABLE_TESTS=FALSE -DCMAKE_BUILD_TYPE=Release ../geodiff
make

Then add the compiled geodiff executable to your local bin directory.

cp geodiff /usr/local/bin/

  1. Create the qf-sync.sh script, used for synchronization between Qfield Cloud Project and PostGIS database. Copy the following content to /usr/local/bin/qf-sync.sh and make the file executable

    #!/bin/bash -e
    
    RUN_FOREVER=1
    
    trap ctrl_c INT TERM
    
    function ctrl_c() {
      RUN_FOREVER=0
    }
    
    if [ $# -ne 1 ]; then
        echo "Usage: ./qf-sync.sh {project.ini}"; exit 1;
    fi
    
    source "${1}"
    
    # hide passwords inside env
    export QFIELDCLOUD_URL="${qf_url}"
    export QFIELDCLOUD_API="${qf_url}"
    export QFIELDCLOUD_USERNAME="${qf_user}"
    export QFIELDCLOUD_PASSWORD="${qf_pass}"
    
    export PGHOST="${pg_host}"
    export PGPORT="${pg_port}"
    export PGDATABASE="${pg_dbname}"
    export PGUSER="${pg_user}"
    export PGPASSWORD="${pg_pass}"
    export PGTBL=${qf_gpkg}
    
    pushd "${HOME}"
    
        source .venv/bin/activate
    
        # create a working directory
        mkdir -p "${data_dir}"
    
        # if forced init, drop table and overwrite exist flag
        if [ "${force_init}" == 'true' ]; then
            psql -c "DROP TABLE IF EXISTS ${pg_schema}.${PGTBL}"
            rm -rf "${data_dir}/*"
        fi
    
        pushd "${data_dir}"
    
        while [ ${RUN_FOREVER} -eq 1 ]; do
    
            UPDATE='0'
    
            if [ -f "${qf_gpkg}.gpkg" ]; then
    
                #get file metadata
                qfieldcloud-cli --json list-files "${qf_proj_id}" | grep -B 2 "${qf_gpkg}" | sed 's/\s\+"\(.*\)":\s"\(.*\)",/\1,\2/' > "${qf_gpkg}.meta"
    
                # check if file is old
                latest_md5sum=$(grep -m1 'md5sum' "${qf_gpkg}.meta" | cut -f2 -d,)
                file_md5sum=$(md5sum "${qf_gpkg}.gpkg" | cut -f1 -d' ')
                if [ "${latest_md5sum}" != "${file_md5sum}" ]; then
                    echo "New md5 sum detected: ${latest_md5sum}"
                    UPDATE='1'  
                fi
            else
                UPDATE='1'
            fi
    
            if [ ${UPDATE} == '1' ]; then
    
                if [ -f "${qf_gpkg}.gpkg" ]; then
                    # save old file, to be able to create a diff
                    mv "${qf_gpkg}.gpkg" "${qf_gpkg}.gpkg.old"
                fi
    
                qfieldcloud-cli download-files --filter "${qf_gpkg}.gpkg" "${qf_proj_id}" "${data_dir}"
    
                if [ -f "${qf_gpkg}.meta" ]; then
                    # create a diff
                    geodiff diff "${qf_gpkg}.gpkg.old" "${qf_gpkg}.gpkg" > diff.bin
                    rm -f "${qf_gpkg}.gpkg.old"
    
                    echo "Applying updates to ${pg_schema}.${gf_gpkg}"
                    geodiff apply --driver postgres "host=${pg_host} port=${pg_port} user=${pg_user} dbname=${pg_dbname} password=${pg_pass}" ${pg_schema} diff.bin
    
                else
    
                    echo "Copying to ${pg_schema}.${gf_gpkg}"
                    geodiff copy --driver-2 postgres "host=${pg_host} port=${pg_port} user=${pg_user} dbname=${pg_dbname} password=${pg_pass}" "${qf_gpkg}.gpkg" ${pg_schema}
                fi
            fi
    
            if [ "${single_run}" == 'true' ]; then
                break;
            fi
    
            sleep ${sleep_time}
        done
    
        popd
    
        deactivate
    popd
    

  2. Setup systemd service If you have multiple projects or want unattended start/restarts, you can use systemd. An example templated service file follows. Only think to change is WorkingDirectory and User.

    [Unit]
    Description=QField Cloud Sync
    
    [Service]
    WorkingDirectory=/home/john/qfsync/
    User=john
    ExecStart=/usr/local/bin/qf-sync.sh %i
    ExecStop=/bin/kill -s SIGTERM $MAINPID
    
    StandardOutput=append:/var/log/qf_sync%i.log
    StandardError=append:/var/log/qf_sync%i.log
    
    [Install]
    WantedBy=multi-user.target