From 065bac0fb2d092d8119c3c45adf42a5e9d8a32b4 Mon Sep 17 00:00:00 2001 From: knokknok <> Date: Wed, 31 Jan 2024 14:56:53 +0100 Subject: [PATCH 1/5] - faster processing of dependencies --- NEWS.md | 2 ++ R/block.R | 2 +- R/cache.R | 13 ++++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index f1c09576a0..f67c606674 100644 --- a/NEWS.md +++ b/NEWS.md @@ -28,6 +28,8 @@ - Fixed broken vignettes, improved CSS for HTML vignettes, and reduced the file sizes. +- Faster processing of cache dependencies (thanks, @knokknok, #2318) + # CHANGES IN knitr VERSION 1.45 ## NEW FEATURES diff --git a/R/block.R b/R/block.R index dee9bdb8c9..dd402a541e 100644 --- a/R/block.R +++ b/R/block.R @@ -345,7 +345,7 @@ eng_r = function(options) { objs, cache_globals(options$cache.globals, code), options$label, options$cache.path ) - dep_auto() + dep_auto(chunk_label=options$label) } if (options$cache < 3) { if (options$cache.rebuild || !cache.exists) block_cache(options, res.orig, objs) diff --git a/R/cache.R b/R/cache.R index b45a619fe6..38abac69e4 100644 --- a/R/cache.R +++ b/R/cache.R @@ -142,6 +142,7 @@ cache_rx = '_[abcdef0123456789]{32}[.](rdb|rdx|RData)$' #' is similar to the effect of the \code{dependson} option. It is supposed to be #' used in the first chunk of a document and this chunk must not be cached. #' @param path Path to the dependency file. +#' @param chunk_label The chunk label of the current code chunk. #' @return \code{NULL}. The dependencies are built as a side effect. #' @note Be cautious about \code{path}: because this function is used in a #' chunk, the working directory when the chunk is evaluated is the directory @@ -152,7 +153,7 @@ cache_rx = '_[abcdef0123456789]{32}[.](rdb|rdx|RData)$' #' @export #' @seealso \code{\link{dep_prev}} #' @references \url{https://yihui.org/knitr/demo/cache/} -dep_auto = function(path = opts_chunk$get('cache.path')) { +dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label=NULL) { # this function should be evaluated in the original working directory owd = setwd(opts_knit$get('output.dir')); on.exit(setwd(owd)) paths = valid_path(path, c('__objects', '__globals')) @@ -164,8 +165,14 @@ dep_auto = function(path = opts_chunk$get('cache.path')) { } nms = intersect(names(knit_code$get()), names(locals)) # guarantee correct order # locals may contain old chunk names; the intersection can be of length < 2 - if (length(nms) < 2) return(invisible(NULL)) - for (i in 2:length(nms)) { + if (is.null(chunk_label)) { + if (length(nms) < 2) return(invisible(NULL)) + chunk_ids <- 2:length(nms) + } else { + chunk_ids <- match(chunk_label, nms) + if (is.na(chunk_ids) || chunk_ids < 2) return(invisible(NULL)) + } + for (i in chunk_ids) { if (length(g <- globals[[nms[i]]]) == 0) next for (j in 1:(i - 1L)) { # check if current globals are in old locals From d075fdef710685585feeeb52c27e426f6065fa82 Mon Sep 17 00:00:00 2001 From: knokknok <> Date: Wed, 31 Jan 2024 15:35:03 +0100 Subject: [PATCH 2/5] Update dep_auto.Rd --- man/dep_auto.Rd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/man/dep_auto.Rd b/man/dep_auto.Rd index 00e18af6e1..04d3f41486 100644 --- a/man/dep_auto.Rd +++ b/man/dep_auto.Rd @@ -4,10 +4,12 @@ \alias{dep_auto} \title{Build automatic dependencies among chunks} \usage{ -dep_auto(path = opts_chunk$get("cache.path")) +dep_auto(path = opts_chunk$get("cache.path"), chunk_label = NULL) } \arguments{ \item{path}{Path to the dependency file.} + +\item{chunk_label}{The chunk label of the current code chunk.} } \value{ \code{NULL}. The dependencies are built as a side effect. From d7437a65b03aef73e25037edd423f6504ca6bcef Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Mon, 1 Apr 2024 10:42:21 -0500 Subject: [PATCH 3/5] cosmetic changes from code review [ci skip] Co-authored-by: atusy <30277794+atusy@users.noreply.github.com> --- R/block.R | 2 +- R/cache.R | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/block.R b/R/block.R index dd402a541e..23e93d8a87 100644 --- a/R/block.R +++ b/R/block.R @@ -345,7 +345,7 @@ eng_r = function(options) { objs, cache_globals(options$cache.globals, code), options$label, options$cache.path ) - dep_auto(chunk_label=options$label) + dep_auto(chunk_label = options$label) } if (options$cache < 3) { if (options$cache.rebuild || !cache.exists) block_cache(options, res.orig, objs) diff --git a/R/cache.R b/R/cache.R index 38abac69e4..550d5edee7 100644 --- a/R/cache.R +++ b/R/cache.R @@ -153,7 +153,7 @@ cache_rx = '_[abcdef0123456789]{32}[.](rdb|rdx|RData)$' #' @export #' @seealso \code{\link{dep_prev}} #' @references \url{https://yihui.org/knitr/demo/cache/} -dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label=NULL) { +dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label = NULL) { # this function should be evaluated in the original working directory owd = setwd(opts_knit$get('output.dir')); on.exit(setwd(owd)) paths = valid_path(path, c('__objects', '__globals')) @@ -167,9 +167,9 @@ dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label=NULL) { # locals may contain old chunk names; the intersection can be of length < 2 if (is.null(chunk_label)) { if (length(nms) < 2) return(invisible(NULL)) - chunk_ids <- 2:length(nms) + chunk_ids = 2:length(nms) } else { - chunk_ids <- match(chunk_label, nms) + chunk_ids = match(chunk_label, nms) if (is.na(chunk_ids) || chunk_ids < 2) return(invisible(NULL)) } for (i in chunk_ids) { From d4c22ec7110705c552a7d6dcf68508fd379f94d6 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Mon, 1 Apr 2024 15:32:43 -0500 Subject: [PATCH 4/5] simplify the code: labels = all_labels() by default, and support a vector of arbitrary labels instead of only a single label --- R/block.R | 2 +- R/cache.R | 20 +++++++------------- man/dep_auto.Rd | 5 +++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/R/block.R b/R/block.R index 23e93d8a87..cdc8a6a57b 100644 --- a/R/block.R +++ b/R/block.R @@ -345,7 +345,7 @@ eng_r = function(options) { objs, cache_globals(options$cache.globals, code), options$label, options$cache.path ) - dep_auto(chunk_label = options$label) + dep_auto(labels = options$label) } if (options$cache < 3) { if (options$cache.rebuild || !cache.exists) block_cache(options, res.orig, objs) diff --git a/R/cache.R b/R/cache.R index 550d5edee7..f5f3c63645 100644 --- a/R/cache.R +++ b/R/cache.R @@ -142,7 +142,8 @@ cache_rx = '_[abcdef0123456789]{32}[.](rdb|rdx|RData)$' #' is similar to the effect of the \code{dependson} option. It is supposed to be #' used in the first chunk of a document and this chunk must not be cached. #' @param path Path to the dependency file. -#' @param chunk_label The chunk label of the current code chunk. +#' @param labels A vector of labels of chunks for which the dependencies will be +#' built. By default, dependencies for all chunks will be built. #' @return \code{NULL}. The dependencies are built as a side effect. #' @note Be cautious about \code{path}: because this function is used in a #' chunk, the working directory when the chunk is evaluated is the directory @@ -153,7 +154,7 @@ cache_rx = '_[abcdef0123456789]{32}[.](rdb|rdx|RData)$' #' @export #' @seealso \code{\link{dep_prev}} #' @references \url{https://yihui.org/knitr/demo/cache/} -dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label = NULL) { +dep_auto = function(path = opts_chunk$get('cache.path'), labels = all_labels()) { # this function should be evaluated in the original working directory owd = setwd(opts_knit$get('output.dir')); on.exit(setwd(owd)) paths = valid_path(path, c('__objects', '__globals')) @@ -163,17 +164,10 @@ dep_auto = function(path = opts_chunk$get('cache.path'), chunk_label = NULL) { warning('corrupt dependency files? \ntry remove ', paste(paths, collapse = '; ')) return(invisible(NULL)) } - nms = intersect(names(knit_code$get()), names(locals)) # guarantee correct order - # locals may contain old chunk names; the intersection can be of length < 2 - if (is.null(chunk_label)) { - if (length(nms) < 2) return(invisible(NULL)) - chunk_ids = 2:length(nms) - } else { - chunk_ids = match(chunk_label, nms) - if (is.na(chunk_ids) || chunk_ids < 2) return(invisible(NULL)) - } - for (i in chunk_ids) { - if (length(g <- globals[[nms[i]]]) == 0) next + nms = intersect(all_labels(), names(locals)) # guarantee correct order + for (i in match(labels, nms)) { + # ignore first chunk (i < 2); locals may contain old chunk names (i will be NA) + if (is.na(i) || i < 2 || length(g <- globals[[nms[i]]]) == 0) next for (j in 1:(i - 1L)) { # check if current globals are in old locals if (any(g %in% locals[[nms[j]]])) diff --git a/man/dep_auto.Rd b/man/dep_auto.Rd index 04d3f41486..5180a2bedc 100644 --- a/man/dep_auto.Rd +++ b/man/dep_auto.Rd @@ -4,12 +4,13 @@ \alias{dep_auto} \title{Build automatic dependencies among chunks} \usage{ -dep_auto(path = opts_chunk$get("cache.path"), chunk_label = NULL) +dep_auto(path = opts_chunk$get("cache.path"), labels = all_labels()) } \arguments{ \item{path}{Path to the dependency file.} -\item{chunk_label}{The chunk label of the current code chunk.} +\item{labels}{A vector of labels of chunks for which the dependencies will be +built. By default, dependencies for all chunks will be built.} } \value{ \code{NULL}. The dependencies are built as a side effect. From 7561aad5b2518a0a655c13c7a8036171767ece55 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Mon, 1 Apr 2024 15:41:31 -0500 Subject: [PATCH 5/5] be more specific in news [ci skip] --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index ce140d9485..1afe5ab1e4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -42,7 +42,7 @@ - `spin()` dropped support for `#-` as the chunk delimiter token. Please use `#+` or `# %%` or `#|` instead. -- Faster processing of cache dependencies (thanks, @knokknok, #2318). +- Faster processing of cache dependencies in `dep_auto()` (thanks, @knokknok, #2318). # CHANGES IN knitr VERSION 1.45