Repository navigation
Conversation
…bjects (#9) For #9 This commit introduces core functionality for handling GDAL Algorithm (GDALG) definition files. It provides `gdalg_read` and `gdalg_write` functions to serialize and deserialize GDALG objects from/to JSON files. Additionally, it adds `gdalg_parse_command_line` for tokenizing GDAL command strings and `validate_gdalg_file` / `validate_gdalg` to ensure GDALG objects and files conform to a defined schema. This enables programmatic definition, storage, and execution of GDAL algorithms.
| # ------------------------------------------------------------------------ | ||
|
|
||
| # read write ------------------------------------------------------------------------------------------------------ | ||
|
|
| alg_cmd <- paste(command_line_parsed[[1]], command_line_parsed[[2]], sep = " ") | ||
| alg_args <- c( | ||
| command_line_parsed[-c(1, 2)], | ||
| "!", "write", "--output", path, "--output-format", "GDALG", |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| "!", "write", "--output", path, "--output-format", "GDALG", | |
| "!", | |
| "write", | |
| "--output", | |
| path, | |
| "--output-format", | |
| "GDALG", |
| res <- rlang::try_fetch({ | ||
| gdalg_alg <- gdalraster::gdal_alg(cmd = alg_cmd, alg_args, parse = FALSE) | ||
| gdalg_alg$run() | ||
| }, error = function(e) { | ||
| FALSE | ||
| }, finally = { | ||
| gdalg_alg$close() | ||
| gdalg_alg$release() | ||
| }) |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| res <- rlang::try_fetch({ | |
| gdalg_alg <- gdalraster::gdal_alg(cmd = alg_cmd, alg_args, parse = FALSE) | |
| gdalg_alg$run() | |
| }, error = function(e) { | |
| FALSE | |
| }, finally = { | |
| gdalg_alg$close() | |
| gdalg_alg$release() | |
| }) | |
| res <- rlang::try_fetch( | |
| { | |
| gdalg_alg <- gdalraster::gdal_alg(cmd = alg_cmd, alg_args, parse = FALSE) | |
| gdalg_alg$run() | |
| }, | |
| error = function(e) { | |
| FALSE | |
| }, | |
| finally = { | |
| gdalg_alg$close() | |
| gdalg_alg$release() | |
| } | |
| ) |
| check_names(x, required = c("type", "command_line", "gdal_version")) | ||
| type <- purrr::pluck(x, "type", .default = NA_character_) | ||
| if (!identical(type, "gdal_streamed_alg")) { | ||
| gdal_abort_check("Provided list must have {.field type} field equal to {.field \"gdal_streamed_alg\"}.", call = call) |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| gdal_abort_check("Provided list must have {.field type} field equal to {.field \"gdal_streamed_alg\"}.", call = call) | |
| gdal_abort_check( | |
| "Provided list must have {.field type} field equal to {.field \"gdal_streamed_alg\"}.", | |
| call = call | |
| ) |
| # constructor ----------------------------------------------------------------------------------------------------- | ||
|
|
||
| new_gdalg <- function(command_line, relative_paths = TRUE, gdal_version = gdal_version_num(), .path = NULL) { | ||
|
|
|
|
||
| gdalg_parse_command_line <- function(command_line) { | ||
| tokens <- strsplit(command_line, "(?<!\\\\)\\s+(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", perl = TRUE)[[1]] | ||
| gsub("^\"|\"$", "", tokens) | ||
| } | ||
|
|
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| gdalg_parse_command_line <- function(command_line) { | |
| tokens <- strsplit(command_line, "(?<!\\\\)\\s+(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", perl = TRUE)[[1]] | |
| gsub("^\"|\"$", "", tokens) | |
| } |
| } | ||
| invisible(x) | ||
| } | ||
|
|
| # | ||
| # ------------------------------------------------------------------------ | ||
|
|
||
|
|
| gdal_abort_check(msg = "Provided {.arg x} is not a valid JSON file path or string", call = rlang::caller_env()) | ||
| } | ||
|
|
||
|
|
|
|
||
|
|
These new GDALG definitions enable streamlined download and processing of TIGER/Line 2025 boundary data from the US Census Bureau. They include pipelines to filter out non-contiguous territories, select relevant attributes, ensure geometry validity, reproject to EPSG:4326, and sort for optimized spatial indexing.
There was a problem hiding this comment.
Code Review
This pull request implements core read, write, parsing, and validation functionality for GDALG files, along with several new utility check functions for names, CRS, and GDALG classes. The review feedback highlights several critical issues: a potential crash in the finally block of gdalg_write() if initialization fails, an overly restrictive name check in as_gdalg.list() for the optional gdal_version field, a lack of defensive validation in gdalg_parse_command_line(), a stubbed implementation of validate_gdalg(), leftover commented-out code in check_file(), and a potential 'length zero' error in check_crs_epsg() when the EPSG is NULL.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| res <- rlang::try_fetch({ | ||
| gdalg_alg <- gdalraster::gdal_alg(cmd = alg_cmd, alg_args, parse = FALSE) | ||
| gdalg_alg$run() | ||
| }, error = function(e) { | ||
| FALSE | ||
| }, finally = { | ||
| gdalg_alg$close() | ||
| gdalg_alg$release() | ||
| }) |
There was a problem hiding this comment.
If gdalraster::gdal_alg() fails to initialize and throws an error, the variable gdalg_alg will not be defined. When the finally block executes, calling gdalg_alg$close() will throw an "object 'gdalg_alg' not found" error, masking the original error and causing an unexpected crash.
Initialize gdalg_alg to NULL outside the try_fetch block, and check if it is non-NULL before calling $close() and $release().
gdalg_alg <- NULL
res <- rlang::try_fetch({
gdalg_alg <<- gdalraster::gdal_alg(cmd = alg_cmd, alg_args, parse = FALSE)
gdalg_alg$run()
}, error = function(e) {
FALSE
}, finally = {
if (!is.null(gdalg_alg)) {
gdalg_alg$close()
gdalg_alg$release()
}
})| # check_names(x, required = c("command_line", "gdal_version")) | ||
| # TODO | ||
| as_gdalg.list <- function(x, ..., .path = NULL, call = rlang::caller_env()) { | ||
| check_names(x, required = c("type", "command_line", "gdal_version")) |
There was a problem hiding this comment.
The gdal_version field is optional in the GDALG schema (and has a fallback default on line 114). Requiring it in check_names() will cause validation to fail for valid GDALG lists that do not specify a version. Please remove "gdal_version" from the required names list.
check_names(x, required = c("type", "command_line"))|
|
||
| # parse ----------------------------------------------------------------------------------------------------------- | ||
|
|
||
| gdalg_parse_command_line <- function(command_line) { |
There was a problem hiding this comment.
If command_line is NULL, NA, or not a character string, strsplit() will throw an error. Since new_gdalg() uses purrr::compact(), a NULL command_line will be omitted from the list, resulting in x$command_line being NULL when passed to gdalg_write().
Add a check_string(command_line) call at the beginning of gdalg_parse_command_line() to ensure defensive input validation.
gdalg_parse_command_line <- function(command_line) {
check_string(command_line)| validate_gdalg <- function(x, schema = pkg_sys_schemas("gdalg.schema.json"), ..., call = rlang::caller_env()) { | ||
| check_gdalg(x) | ||
| } |
There was a problem hiding this comment.
The validate_gdalg function is currently a stub that only calls check_gdalg(x) (which checks class inheritance). It does not perform any schema validation, despite accepting a schema argument. If the intent is to validate the in-memory GDALG object against the schema, you should serialize it to JSON (or use an appropriate list validator) and run the schema validation on it.
| # ext <- gsub(".", "", ext, fixed = TRUE) | ||
| ext <- gsub("^\\.", "", ext) | ||
| # ext_parts <- strsplit(ext, ".", fixed = TRUE)[[1]] | ||
| # if (length(ext_parts) > 1L) { | ||
| # # for each ext_part, check, in order, it against the initial path, then the extension of the initial path sans ext, ... | ||
| # for (i in seq_along(ext_parts)) { | ||
| # ext_part <- ext_parts[i] | ||
| # if (tolower(tools::file_ext(x)) == ext_part) { | ||
| # return(invisible(x)) | ||
| # } | ||
| # x <- sub(paste0("\\.", tools::file_ext(x), "$"), "", x) | ||
| # } | ||
| # } |
| epsg <- sf::st_crs(x)$epsg | ||
| if (is.na(epsg) || epsg != expected_epsg) { |
There was a problem hiding this comment.
If sf::st_crs(x)$epsg returns NULL or is empty, is.na(epsg) will evaluate to logical(0), causing the if condition to throw an "argument is of length zero" error.
Use a more defensive check such as is.null(epsg) || is.na(epsg) || epsg != expected_epsg to handle this safely.
epsg <- sf::st_crs(x)$epsg
if (is.null(epsg) || is.na(epsg) || epsg != expected_epsg) {|
|
||
|
|
Captures research and design decisions for a future vector introspection layer, particularly detailing the complex nuances of Feature ID (FID) handling in GDAL. This document aims to prevent re-derivation of hard-won knowledge, guiding future implementation efforts.
…bjects (#9) For #9 This commit introduces core functionality for handling GDAL Algorithm (GDALG) definition files. It provides `gdalg_read` and `gdalg_write` functions to serialize and deserialize GDALG objects from/to JSON files. Additionally, it adds `gdalg_parse_command_line` for tokenizing GDAL command strings and `validate_gdalg_file` / `validate_gdalg` to ensure GDALG objects and files conform to a defined schema. This enables programmatic definition, storage, and execution of GDAL algorithms.
These new GDALG definitions enable streamlined download and processing of TIGER/Line 2025 boundary data from the US Census Bureau. They include pipelines to filter out non-contiguous territories, select relevant attributes, ensure geometry validity, reproject to EPSG:4326, and sort for optimized spatial indexing.
GDALG Support
Initial Commit:
For #9
This commit introduces core functionality for handling GDAL Algorithm (GDALG) definition files. It provides
gdalg_readandgdalg_writefunctions to serialize and deserialize GDALG objects from/to JSON files.Additionally, it adds
gdalg_parse_command_linefor tokenizing GDAL command strings andvalidate_gdalg_file/validate_gdalgto ensure GDALG objects and files conform to a defined schema. This enables programmatic definition, storage, and execution of GDAL algorithms.