diff --git a/DESCRIPTION b/DESCRIPTION index ae93854..c2203b6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: reportifyr Title: Reproducible Reporting Made Simple with R -Version: 0.3.2 +Version: 0.3.3 Authors@R: c( person("Jacob", "Dumbleton", , "jacob@a2-ai.com", role = c("aut", "cre")), person("Matthew", "Smith", , "matthews@a2-ai.com", role = "aut"), @@ -39,7 +39,7 @@ Imports: processx, purrr, rlang, - rstudioapi, + this.path, tictoc, yaml Suggests: diff --git a/NEWS.md b/NEWS.md index f18c4fe..0274d7d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# reportifyr 0.3.3 +## Bug Fixes + +* Fixed an issue where the source path of an object being written out with `write_object_metadata()` during a quarto render was being captured as the intermediate `.rmarkdown`. + # reportifyr 0.3.2 ## Improvements diff --git a/R/utils.R b/R/utils.R index 11b51c6..23116b9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -151,7 +151,7 @@ get_uv_path <- function(quiet = FALSE) { # Use default expansion home_dir <- path.expand("~") } - + if (.Platform$OS.type == "windows") { # Windows paths uv_paths <- c( @@ -212,25 +212,70 @@ get_uv_version <- function(uv_path) { #' @noRd find_project_root <- function(start_path = getwd()) { current_path <- normalizePath(start_path) - + while (TRUE) { # Look for any .*_init.json file (e.g., .report_init.json, .custom_init.json) init_files <- list.files(current_path, pattern = "^\\.[^.]*_init\\.json$", full.names = TRUE, all.files = TRUE) if (length(init_files) > 0) { return(current_path) } - + # Move up one directory parent_path <- dirname(current_path) - + # If we've reached the root directory, stop if (parent_path == current_path) { break } - + current_path <- parent_path } - + # Return NULL if not found return(NULL) } + +detect_quarto_render <- function() { + log4r::debug(.le$logger, "Starting detect_quarto_render()") + + # --- Detect Quarto context --- + quarto_vars <- Sys.getenv(c("QUARTO_PROJECT_ROOT", "QUARTO_BIN_PATH", "QUARTO_RENDER_TOKEN")) + is_quarto <- any(quarto_vars != "") + log4r::debug(.le$logger, paste0("Quarto environment vars detected: ", is_quarto)) + + if (!is_quarto) { + log4r::debug(.le$logger, "Not running in a Quarto context, returning NULL") + return(NULL) + } + + # --- Get current input --- + current <- tryCatch(knitr::current_input(), error = function(e) NULL) + log4r::debug(.le$logger, paste0("knitr::current_input() returned: ", ifelse(is.null(current), "NULL", current))) + + # --- Validate current file pattern --- + if (is.null(current) || !grepl("\\.(Rmd|rmarkdown)$", current, ignore.case = TRUE)) { + log4r::debug(.le$logger, "Current input is NULL or not an .Rmd/.rmarkdown file, returning NULL") + return(NULL) + } + + # --- Attempt to resolve .qmd equivalent --- + qmd_candidate <- sub("\\.(rmd|rmarkdown)$", ".qmd", basename(current)) + project_root <- Sys.getenv("QUARTO_PROJECT_ROOT", unset = getwd()) + qmd_path <- file.path(project_root, qmd_candidate) + log4r::debug(.le$logger, paste0("Candidate .qmd path: ", qmd_path)) + + if (file.exists(qmd_path)) { + log4r::info(.le$logger, paste0( + "Detected Quarto render: .Rmd intermediate '", current, + "' mapped to existing .qmd: ", qmd_path + )) + return(normalizePath(qmd_path)) + } else { + log4r::warn(.le$logger, paste0( + "Quarto environment detected, but .qmd not found at: ", qmd_path, + ", returning NULL" + )) + return(NULL) + } +} + diff --git a/R/write_object_metadata.R b/R/write_object_metadata.R index 78e45fa..3bf2563 100644 --- a/R/write_object_metadata.R +++ b/R/write_object_metadata.R @@ -49,50 +49,44 @@ write_object_metadata <- function( hash <- digest::digest(file = object_file, algo = "blake3") log4r::info(.le$logger, paste0("Generated file hash: ", hash)) - source_path <- tryCatch( - { - # Check if the script is being sourced - src_path <- if (!is.null(sys.frame(1)$ofile)) { - normalizePath(sys.frame(1)$ofile) # Path of the currently sourced file - } else if (!is.null(knitr::current_input())) { - normalizePath(knitr::current_input()) - } else if ( - requireNamespace("rstudioapi", quietly = TRUE) && - rstudioapi::isAvailable() - ) { - context <- rstudioapi::getSourceEditorContext() - if (!is.null(context$path) && nzchar(context$path)) { - normalizePath(context$path) - } else { - normalizePath("Object created from console") - } - } else if (!is.null(rmarkdown::metadata$input_file)) { - normalizePath(rmarkdown::metadata$input_file) - } else if (!is.null(getOption("knitr.in.file"))) { - normalizePath(getOption("knitr.in.file")) - } else if (testthat::is_testing()) { - normalizePath(testthat::test_path()) + source_path <- tryCatch({ + qmd_path <- detect_quarto_render() + if (!is.null(qmd_path)) { + log4r::info(.le$logger, + paste0("Detected Quarto render; using .qmd file: ", qmd_path)) + qmd_path + } else if (requireNamespace("this.path", quietly = TRUE)) { + sp <- this.path::this.path() + if (!is.null(sp) && nzchar(sp)) { + sp <- normalizePath(sp) + log4r::info(.le$logger, + paste0("Source path detected via this.path: ", sp)) + sp } else { - stop("Unable to detect input file") + log4r::warn(.le$logger, + "this.path did not return a valid script path; setting placeholder") + "SOURCE_PATH_NOT_DETECTED" } - src_path - }, - error = function(e) { - log4r::error(.le$logger, "Error detecting source file path") - stop(e) + } else { + log4r::warn(.le$logger, + "Unable to detect source path via Quarto or this.path(); setting placeholder") + "SOURCE_PATH_NOT_DETECTED" } - ) - - log4r::info(.le$logger, paste0("Source file path detected: ", source_path)) + }, + error = function(e) { + log4r::warn(.le$logger, + paste0("Error detecting source path: ", e$message)) + "SOURCE_PATH_NOT_DETECTED" + }) # Find project root directory (containing .*_init.json) project_root <- find_project_root() - + if (is.null(project_root)) { log4r::error(.le$logger, "Could not find project root directory (no *_init.json file found)") stop("Could not find project root directory. Make sure you're in a reportifyr project (run initialize_report_project() first)") } - + # Convert source path to relative path from project root source_path_relative <- fs::path_rel(source_path, project_root) log4r::info(.le$logger, paste0("Source file path (relative): ", source_path_relative)) diff --git a/rproject.toml b/rproject.toml index dd8015f..2999f0e 100644 --- a/rproject.toml +++ b/rproject.toml @@ -7,9 +7,11 @@ r_version = "4.4" repositories = [ #{ alias = "PRISM", url = "https://prism.dev.a2-ai.cloud/rpkgs/stratus/2025-07-28/" }, {alias = "ppm", url = "https://packagemanager.posit.co/cran/latest"}, + {alias = "CRAN", url = "https://cran.r-project.org"}, ] dependencies = [ "devtools", {name = "reportifyr", path = ".", dependencies_only = true, install_suggestions = true }, + {name = "gdtools", repository = "CRAN"}, ]