R/grin2.retrieve.annotation.resource.R

Defines functions grin2.retrieve.annotation.resource

#' Retrieve a GRIN2 Annotation Resource
#'
#' Internal helper function used to retrieve a pre-generated GRIN2 annotation
#' resource, verify its checksum, optionally cache it locally, and read the
#' annotation object.
#'
#' @param resource.row A one-row data frame from
#'   \code{grin2.annotation.resources()} describing the annotation resource to
#'   retrieve, including its annotation type, file name, URL, bundle version,
#'   and expected MD5 checksum.
#' @param genome.assembly Character string specifying the genome assembly.
#' @param ensembl.version Integer specifying the Ensembl release.
#' @param cache Logical indicating whether the verified annotation file should
#'   be cached locally.
#' @param cache.dir Character string specifying the cache directory.
#' @param force.download Logical indicating whether the resource should be
#'   downloaded even when a valid cached copy is available.
#' @param quiet Logical indicating whether status messages should be
#'   suppressed.
#'
#' @return The requested annotation object read from the verified resource file.
#'
#' @keywords internal
#' @noRd
grin2.retrieve.annotation.resource <- function(resource.row,
                                               genome.assembly,
                                               ensembl.version,
                                               cache,
                                               cache.dir,
                                               force.download,
                                               quiet)
{
  resource.type <- as.character(resource.row$annotation.type[[1L]])
  resource.url <- as.character(resource.row$url[[1L]])
  resource.file.name <- as.character(resource.row$file.name[[1L]])
  expected.md5 <- as.character(resource.row$md5[[1L]])
  bundle.version <- as.character(resource.row$bundle.version[[1L]])

  # Use the persistent cache or a temporary destination
  destination.file <- if (isTRUE(cache))
  {
    file.path(cache.dir, resource.file.name)
  } else {
    tempfile(pattern = paste0("GRIN2_", resource.type, "_"),
             fileext = ".rds")
  }

  # Remove the temporary annotation file when caching is disabled
  if (!isTRUE(cache))
    on.exit(unlink(destination.file), add = TRUE)

  file.is.valid <- FALSE

  ####################################################################
  # Check an existing cached file
  ####################################################################

  if (file.exists(destination.file) && !isTRUE(force.download))
  {
    if (is.na(expected.md5) || !nzchar(expected.md5))
    {
      file.is.valid <- TRUE
    } else {
      observed.md5 <- unname(tools::md5sum(destination.file))

      file.is.valid <- !is.na(observed.md5) &&
        identical(tolower(observed.md5), tolower(expected.md5))
    }

    if (!file.is.valid && !isTRUE(quiet))
      message("The cached ", resource.type,
              " annotation failed checksum verification and will be downloaded again.")
  }

  ####################################################################
  # Download resource if necessary
  ####################################################################

  if (!file.exists(destination.file) ||
      isTRUE(force.download) ||
      !file.is.valid)
  {
    temporary.download <- tempfile(
      pattern = paste0(resource.file.name, "_"),
      fileext = ".download"
    )

    on.exit(unlink(temporary.download), add = TRUE)

    if (!isTRUE(quiet))
      message("Downloading GRIN2 ", resource.type, " annotation for ",
              genome.assembly, ", Ensembl release ", ensembl.version, "...")

    download.status <- tryCatch(
      {
        utils::download.file(url = resource.url,
                             destfile = temporary.download,
                             mode = "wb",
                             quiet = quiet)
      },
      error = function(e)
      {
        stop(paste0("Failed to download the ", resource.type, " annotation.\n",
                    "Source: ", resource.url, "\n",
                    "Original error: ", conditionMessage(e)),
             call. = FALSE)
      })

    if (is.null(download.status) ||
        download.status != 0L ||
        !file.exists(temporary.download))
      stop(paste0("The ", resource.type,
                  " annotation download did not complete successfully."),
           call. = FALSE)

    ####################################################################
    # Verify downloaded file
    ####################################################################

    if (!is.na(expected.md5) && nzchar(expected.md5))
    {
      observed.md5 <- unname(tools::md5sum(temporary.download))

      if (is.na(observed.md5) ||
          !identical(tolower(observed.md5), tolower(expected.md5)))
        stop(paste0("Checksum verification failed for the downloaded ",
                    resource.type, " annotation.\n",
                    "Expected MD5: ", expected.md5, "\n",
                    "Observed MD5: ", observed.md5),
             call. = FALSE)
    }

    ####################################################################
    # Copy verified file to its destination
    ####################################################################

    copied.successfully <- file.copy(from = temporary.download,
                                     to = destination.file,
                                     overwrite = TRUE)

    if (!isTRUE(copied.successfully))
      stop(paste0("The downloaded annotation could not be copied to: ",
                  destination.file),
           call. = FALSE)
  }

  ####################################################################
  # Read annotation
  ####################################################################

  annotation.object <- tryCatch(
    readRDS(destination.file),
    error = function(e)
    {
      stop(paste0("The ", resource.type,
                  " annotation file could not be read.\n",
                  "File: ", destination.file, "\n",
                  "Original error: ", conditionMessage(e)),
           call. = FALSE)
    })

  if (!isTRUE(quiet))
  {
    message("Using GRIN2 ", resource.type, " annotation: ",
            genome.assembly, ", Ensembl release ", ensembl.version,
            ", bundle ", bundle.version, ".")

    if (isTRUE(cache))
      message("Cached file: ", destination.file)
  }

  annotation.object
}

Try the GRIN2 package in your browser

Any scripts or data that you put into this service are public.

GRIN2 documentation built on Aug. 22, 2026, 5:09 p.m.