Skip to contents

Refreshes the layers of a project's background_layers.gpkg from their sources, reconciled against the project's manifest (see rfp_manifest_read()) when one exists, else the template registry. Replace-only: refresh = manifest-intersect-gpkg per source type; manifest-not-gpkg layers are ADDED (the manifest edit was the deliberate act); frozen layers are untouched; gpkg-not-manifest layers are flagged but never removed. The legacy unprefixed AOI layer (#71) is removed when present.

Usage

rfp_project_update(
  path,
  watershed_groups,
  manifest = NULL,
  template = NULL,
  add = NULL,
  dry_run = TRUE,
  path_hold = NULL,
  dir_layers = NULL,
  file_gpkg = NULL,
  layout = NULL,
  s3_base = NULL,
  lookups = NULL
)

Arguments

path

Character. Path to the project directory containing background_layers.gpkg.

watershed_groups

Character vector of 4-letter uppercase BC watershed group codes (e.g., c("BULK", "KLUM")). Interpolated into source SQL, so the format is enforced strictly.

manifest

NULL (default), a path to a manifest CSV, or a manifest data frame. NULL auto-discovers rfp_manifest.csv at the project root and falls back to registry mode when absent. The mode in use is always printed - no silent switch.

template

Character. Template for registry mode, and the style source for layers the project .qgs does not reference. NULL (default) uses the template recorded in the project's rfp_project.json, falling back to "bcfishpass_mobile" for a project created before that was written. An explicit value always wins.

add

Character vector of registry layers to add (registry mode only - in manifest mode, edit the manifest instead). Default NULL.

dry_run

Logical. Default TRUE - print the plan and exit.

path_hold

Character. Root directory for pre-refresh backups. Default NULL uses a hold/ directory NEXT TO the project (never inside it - backups inside a Mergin project would sync to the server on the next push).

dir_layers

Character. Directory holding one GeoPackage per layer. NULL (default) resolves getOption("rfp.dir_layers").

file_gpkg

Character. Single-GeoPackage file name for projects that have not been split. NULL (default) resolves getOption("rfp.file_gpkg").

layout

Character. "split", "monolith", or NULL (default) to detect from the project directory.

s3_base

Character. Object-storage base for the aws pass, or NULL (default) to take the project's own recorded base and fall back to the shipped host. Re-resolved after a Mergin pull, because the record syncs (#268).

lookups

Named list of override CSVs for the osm, url and stac tiers, merged row-wise over the shipped lookups. Passed straight to rfp_source(); see there and rfp_source_lookup(). NOT recorded in the project's identity record the way s3_base is - the file lives in the caller's repo, so a path written into a Mergin-synced project would be machine-specific and would sync to field devices (rfp#285).

Value

Invisibly, a list with plan (per-source-type refresh/add lists), and on execute runs audit (the post-refresh rfp_project_audit() result), path_hold (the backup directory), and hashes (per-table content fingerprints via .gpkg_hash_tables()).

Details

DRY-RUN by default: prints the plan and exits - nothing touches the project or Mergin until dry_run = FALSE. For a Mergin project (.mergin/ present) an execute run pulls first, recomputes the plan against post-pull state, and backs up the gpkg + .qgs + habitat_lateral.tif to path_hold before any write. Never pushes

Refreshed layers that carry a shipped natural key (see inst/lookups/rfp_natural_keys.csv, e.g. bcfishpass.streams_vw -> segmented_stream_id) are REIDENTIFIED on execute: each surviving key keeps the feature id it had before the refresh, so a re-download that reassigns ids no longer churns every row and the Mergin push is a true-delta changeset instead of the whole file (#12). The reidentify is fail-closed - a layer whose key is dropped by a column keep-list, or is not unique in the fresh data, silently falls back to naive ids (a full push for that layer) - so any keep-list applied to a keyed layer must retain its natural key.

Styling

On execute, the background GeoPackages are re-styled from the project's own .qgs, so a layer added since the last run carries its symbology into layer_styles — the table QGIS reads on Add Layer.

A layer the .qgs does not reference — one added since creation — is styled from the project's recorded template instead, so it arrives styled on its first Add Layer rather than needing to be styled by hand.

That second source is scoped to tables the project's own .qgs did not cover, and the scoping is what makes it safe. Two overlapping sources would replace a symbology restyled in QGIS Desktop on every run, and leave a renamed layer trading useAsDefault between them forever. With no overlap neither can happen, and re-styling an unchanged layer leaves its file byte-identical, so it does not dirty a project for the next Mergin push.

A project with no recorded template (created before rfp 0.15.0) skips the second pass entirely and behaves as before.

Examples

if (FALSE) { # \dontrun{
# Dry run - review the plan
rfp_project_update("~/Projects/gis/test_kotl_20260505", "KOTL")

# Execute, then verify in QGIS desktop before pushing
rfp_project_update("~/Projects/gis/test_kotl_20260505", "KOTL",
                   dry_run = FALSE)
rfp_mergin_push("~/Projects/gis/test_kotl_20260505")
} # }