Skip to content

Commit

Permalink
news funs (#34)
Browse files Browse the repository at this point in the history
* news funs
  • Loading branch information
Polkas authored Sep 23, 2024
1 parent 7d01e52 commit 535122a
Show file tree
Hide file tree
Showing 26 changed files with 525 additions and 84 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ BugReports: https://github.com/Polkas/pacs/issues
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
RoxygenNote: 7.2.2
Depends: R (>= 3.5.0)
Imports:
curl,
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export(match_flavors)
export(pac_checkpage)
export(pac_checkred)
export(pac_compare_namespace)
export(pac_compare_news)
export(pac_compare_versions)
export(pac_deps)
export(pac_deps_dev)
Expand All @@ -28,6 +29,7 @@ export(pac_islast)
export(pac_last)
export(pac_lifeduration)
export(pac_namespace)
export(pac_news)
export(pac_size)
export(pac_timemachine)
export(pac_true_size)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# pacs 0.5.1.9000

* add new functions: pac_news and pac_compare_news. Functions are NEWS file related.
* update the tinyverse vignette with a new badge url.
* fix a problem with app_deps on R 3.6.
* improve code base.

# pacs 0.5.1

Expand Down
89 changes: 79 additions & 10 deletions R/comapre.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,10 @@ pac_compare_versions <- function(pac,
lib.loc = .libPaths(),
repos = "https://cran.rstudio.com/") {
fields <- expand_dependency(fields)
stopifnot((length(pac) == 1) && is.character(pac))
stopifnot(is.null(old) || (length(old) == 1) && is.character(old))
stopifnot(is.null(new) || (length(new) == 1) && is.character(new))
stopifnot(is.character(repos))
stopifnot(is.null(lib.loc) || (all(lib.loc %in% .libPaths()) && (length(list.files(lib.loc)) > 0)))
validate_compare_input(pac, old, new, lib.loc, repos)
stopifnot(is_online())


if (isFALSE(pac_isin(pac, repos))) {
message(
sprintf(
Expand Down Expand Up @@ -101,13 +98,10 @@ pac_compare_namespace <- function(pac,
new = NULL,
lib.loc = .libPaths(),
repos = "https://cran.rstudio.com/") {
stopifnot((length(pac) == 1) && is.character(pac))
stopifnot(is.null(old) || (length(old) == 1) && is.character(old))
stopifnot(is.null(new) || (length(new) == 1) && is.character(new))
stopifnot(is.character(repos))
stopifnot(is.null(lib.loc) || (all(lib.loc %in% .libPaths()) && (length(list.files(lib.loc)) > 0)))
validate_compare_input(pac, old, new, lib.loc, repos)
stopifnot(is_online())


if (isFALSE(pac_isin(pac, repos))) {
message(
sprintf(
Expand Down Expand Up @@ -162,3 +156,78 @@ pac_compare_namespace <- function(pac,

structure(result, package = pac, old = old, new = new)
}

#' Compare NEWS files between specific CRAN packages versions
#' @description using the remote github CRAN mirror to compare NEWS files between specific packages versions.
#' @inheritParams standard_args
#' @param repos `character` vector repositories URLs to use. Used only for the validation. Default `https://cran.rstudio.com/`
#' @return `character` with NEWS content between specific versions.
#' @export
#' @examples
#' \dontrun{
#' pacs::pac_compare_news("shiny", "1.0.0", "1.6.0")
#' # local version to newest one
#' pacs::pac_compare_news("shiny")
#' }
pac_compare_news <- function(pac,
old = NULL,
new = NULL,
lib.loc = .libPaths(),
repos = "https://cran.rstudio.com/") {


validate_compare_input(pac, old, new, lib.loc, repos)
stopifnot(is_online())

if (isFALSE(pac_isin(pac, repos))) {
return(NA)
}

if (is.null(old)) {
stopifnot(pac %in% rownames(installed_packages(lib.loc = lib.loc)))
old <- pac_description(pac, local = TRUE)$Version
}

if (is.null(new)) {
new <- pac_last(pac)
}

stopifnot(utils::compareVersion(new, old) >= 0)

if (utils::compareVersion(new, old) == 0) {
return(NA)
}

version_pattern <- function(version) {
paste0("#.*", version)
}

last_version <- pac_last(pac, repos = repos)
pac_news <- pac_news(pac, last_version, lib.loc = lib.loc, repos = repos)


old_version_reg <- regexpr(version_pattern(old), pac_news)
which_matched_old <- which(old_version_reg > 0)[1]
old_version_pos <- if (isTRUE(which_matched_old > 0)) {
which_matched_old
} else {
NA
}

new_version_reg <- regexpr(version_pattern(new), pac_news)
which_matched_new <- which(new_version_reg > 0)[1]
new_version_pos <- if (isTRUE(which_matched_new > 0)) {
which_matched_new
} else {
NA
}

if (is.na(old_version_pos) || is.na(new_version_pos)) {
return(NA)
}

result <- pac_news[new_version_pos:max(c(old_version_pos - 1, 1))]
result
}


11 changes: 2 additions & 9 deletions R/description.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ pac_description <- function(pac,
local = FALSE,
lib.loc = .libPaths(),
repos = "https://cran.rstudio.com/") {
stopifnot((isFALSE(local)) ||
(isTRUE(local) && (is.null(version) || isTRUE(utils::packageDescription(pac, lib.loc = lib.loc)$Version == version))))
stopifnot(all(c(is.null(version), is.null(at))) || xor(!is.null(version), !is.null(at)))
stopifnot(is.null(at) || inherits(at, "Date"))
stopifnot(length(pac) == 1 && is.character(pac))
stopifnot(is.null(lib.loc) || (all(lib.loc %in% .libPaths()) && (length(list.files(lib.loc)) > 0)))
stopifnot(is.null(version) || (length(version) == 1 && is.character(version)))
validate_pac_input(pac, version, at, local, lib.loc, repos)

is_installed <- isTRUE(pac %in% rownames(installed_packages(lib.loc = lib.loc)))
if ((!is_installed && local) || (!local && !is_online())) {
Expand Down Expand Up @@ -84,12 +78,11 @@ pac_description_dcf_raw <- function(pac, version, repos = "https://cran.rstudio.
silent = TRUE
)
if (inherits(tt, "try-error")) {
result <- cran_archive_file(pac, version, repos, "DESCRIPTION")
result <- read_cran_file(pac, version, "DESCRIPTION", repos)
} else {
result <- as.list(read.dcf(ee)[1, ])
}
unlink(ee)

structure(result, package = pac, version = version)
}

Expand Down
10 changes: 2 additions & 8 deletions R/namespace.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,7 @@
#' pacs::pac_namespace("memoise", local = TRUE)
#' }
pac_namespace <- function(pac, version = NULL, at = NULL, local = FALSE, lib.loc = .libPaths(), repos = "https://cran.rstudio.com/") {
stopifnot((isFALSE(local)) ||
(isTRUE(local) && (is.null(version) || isTRUE(utils::packageDescription(pac, lib.loc = lib.loc)$Version == version))))
stopifnot(all(c(is.null(version), is.null(at))) || xor(!is.null(version), !is.null(at)))
stopifnot(is.null(at) || inherits(at, "Date"))
stopifnot(length(pac) == 1 && is.character(pac))
stopifnot(is.null(lib.loc) || (all(lib.loc %in% .libPaths()) && (length(list.files(lib.loc)) > 0)))
stopifnot(is.null(version) || (length(version) == 1 && is.character(version)))
validate_pac_input(pac, version, at, local, lib.loc, repos)

is_installed <- isTRUE(pac %in% rownames(installed_packages(lib.loc = lib.loc)))
if ((!is_installed && local) || (!local && !is_online())) {
Expand Down Expand Up @@ -86,7 +80,7 @@ pac_readnamespace_raw <- function(pac, version, repos = "https://cran.rstudio.co
silent = TRUE
)
if (inherits(tt, "try-error")) {
result <- cran_archive_file(pac, version, repos, "NAMESPACE")
result <- read_cran_file(pac, version, "NAMESPACE", repos)
} else {
result <- readLines(ee, warn = FALSE)
unlink(ee)
Expand Down
94 changes: 94 additions & 0 deletions R/news.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#' Get NEWS for a package
#' @description Get NEWS for a package from CRAN or local
#' @inheritParams standard_args
#' @param repos `character` vector repositories URLs to use. Used only for the validation. Default `https://cran.rstudio.com/`
#' @return `character` with NEWS content.
#' @note Results are cached for 30 minutes with `memoise` package.
#' @export
#' @examples
#' \dontrun{
#' pacs::pac_news("dplyr", version = "0.8.0")
#' pacs::pac_news("dplyr", at = as.Date("2019-02-01"))
#' }
pac_news <- function(
pac,
version = NULL,
at = NULL,
local = FALSE,
lib.loc = .libPaths(),
repos = "https://cran.rstudio.com/"
) {

validate_pac_input(pac, version, at, local, lib.loc, repos)

is_installed <- isTRUE(pac %in% rownames(installed_packages(lib.loc = lib.loc)))
if ((!is_installed && local) || (!local && !is_online())) {
return(NA)
}

version_installed <- if (is_installed) {
utils::packageDescription(pac)$Version
} else {
NA
}
version_null <- is.null(version)

if (local && is_installed && is.null(at) && (version_null || isTRUE(utils::compareVersion(version, version_installed) == 0))) {
news_name <- intersect(list.files(system.file(package = pac)), c("NEWS.md", "NEWS", "NEWS.Rmd"))
if (length(news_name) == 0) {
return(NA)
}
return(readLines(system.file(package = pac, news_name[1]), warn = FALSE))
} else if (isTRUE(is_isin(pac, "https://cran.rstudio.com/"))) {
last_version <- pac_last(pac, repos = repos)
version <- if (!version_null) {
version
} else if (!is.null(at)) {
vv <- utils::tail(pac_timemachine(pac, at = at)$Version, 1)
if (isNA(vv) || is.null(vv)) {
return(NA)
}
vv
} else {
last_version
}
news_lines <- pac_readnews(pac, version, repos)
if (isTRUE(is.na(news_lines))) {
return(NA)
} else if (length(news_lines) == 0) {
return(NA)
} else {
return(news_lines)
}
} else {
return(NA)
}
}


pac_readnews_raw <- function(pac, version, repos = "https://cran.rstudio.com/") {
ee <- tempfile()
d_url <- sprintf(
"https://raw.githubusercontent.com/cran/%s/%s/NEWS",
pac,
version
)
tt <- try(
{
suppressWarnings(utils::download.file(d_url,
destfile = ee,
quiet = TRUE
))
},
silent = TRUE
)
if (inherits(tt, "try-error")) {
result <- read_cran_file(pac, version, "NEWS", repos)
} else {
result <- readLines(ee)
unlink(ee)
}
result
}

pac_readnews <- memoise::memoise(pac_readnews_raw, cache = cachem::cache_mem(max_age = 30 * 60))
58 changes: 58 additions & 0 deletions R/read_cran_file.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#' Read a file from CRAN
#' @description Read a file from CRAN package source.
#' @inheritParams standard_args
#' @keywords internal
read_cran_file <- function(pac, version, file, repos = "https://cran.rstudio.com/") {
stopifnot(is_online())

last_version <- pac_last(pac, repos)

if (isTRUE(!is.null(version) && version != last_version)) {
base_url <- sprintf("https://cran.r-project.org/src/contrib/Archive/%s", pac)
} else {
base_url <- "https://cran.r-project.org/src/contrib"
version <- last_version
}

d_url <- sprintf(
"%s/%s_%s.tar.gz",
base_url,
pac,
version
)

temp_tar <- tempfile(fileext = ".tar.gz")

download <- try(
expr = {
suppressWarnings(utils::download.file(d_url,
destfile = temp_tar,
quiet = TRUE
))
},
silent = TRUE
)

if (inherits(download, "try-error")) {
result <- NA
} else {
temp_dir <- tempdir()
utils::untar(temp_tar, exdir = temp_dir)
if (file == "DESCRIPTION") {
result <- as.list(read.dcf(file.path(temp_dir, pac, "DESCRIPTION"))[1, ])
} else if (file == "NAMESPACE") {
result <- readLines(file.path(temp_dir, pac, "NAMESPACE"), warn = FALSE)
} else if (file == "NEWS") {
news_name <- intersect(list.files(file.path(temp_dir, pac)), c("NEWS.md", "NEWS", "NEWS.Rmd"))
if (length(news_name) == 0) {
warning("NEWS file not found")
return(NA)
}
result <- readLines(file.path(temp_dir, pac, news_name[1]), warn = FALSE)
} else {
stop("Invalid file name")
}
}
unlink(temp_tar)
result
}
31 changes: 31 additions & 0 deletions R/read_github_file.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#' Read a file from a GitHub CRAN repository
#' @description Read a file from a GitHub CRAN repository.
#' @inheritParams standard_args
#' @note if the file is not found in the GitHub repository, it will try to find it in the CRAN archive.
#' @keywords internal
read_github_file <- function(pac, version, file, repos = "https://cran.rstudio.com/") {
stopifnot(is_online())
ee <- tempfile()
d_url <- sprintf(
"https://raw.githubusercontent.com/cran/%s/%s/%s",
pac,
version,
file
)
tt <- try(
expr = {
suppressWarnings(utils::download.file(d_url,
destfile = ee,
quiet = TRUE
))
},
silent = TRUE
)
if (inherits(tt, "try-error")) {
result <- read_cran_file(pac, version, file, repos)
} else {
result <- readLines(ee)
unlink(ee)
}
result
}
1 change: 1 addition & 0 deletions R/template_args.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#' Default: `list(scope = character(0), flavor = NULL)`
#' @param description_v `logical` if the dependencies version should be taken from description files, minimal required. By default installed versions are taken. Default: `FALSE`
#' @param exclude_joint `integer` exclude packages which are dependencies of at least N other packages, not count main package dependencies. Default: `0`
#' @param file `character` file name to read. Possible values are `DESCRIPTION`, `NEWS` and `NAMESPACE`.
#' @param fields `character` vector listing the types of dependencies, a subset of `c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances")`.
#' Character string "all" is shorthand for that vector, character string "most" for the same vector without "Enhances", character string "strong" (default) for the first three elements of that vector.
#' Default: `c("Depends", "Imports", "LinkingTo")`
Expand Down
Loading

0 comments on commit 535122a

Please sign in to comment.