rdevtoolsroxygen2package-development

How can I automatically add/update Depends/Imports/Suggests versions in DESCRIPTION?


I like to keep my R packages up to date, and in developing my own package, I want to stick to @Hadley's advice:

Generally, it’s always better to specify the version and to be conservative about which version to require. Unless you know otherwise, always require a version greater than or equal to the version you’re currently using.

So, I'll need some of those here in DESCRIPTION:

Imports:
 knitr (>= 1.13),
 rmarkdown (>= 1.0)

Is there an existing tool to programmatically update the versions of dependencies based on the packages I currently have installed?

I know this is a small thing and I can do this manually, but I just know this is the kind of thing that is easily forgotten.

Using the locally installed version of a package as a minimum dependency also seems to make sense because I tested / build with those dependencies.

Is there a reason why I shouldn't do this?


Solution

  • This shld do what you ask (well, you still need to cut/paste the output into DESCRIPTION :-)

    #' Add curent version string to package dependencies
    #'
    #' Will \code{cat} out a cut/paste-able set of fields for a
    #' \code{DESCRIPTION} file with minimum required versions for
    #' each package based upon currently available package vesions
    #' in CRAN.
    #'
    #' @param pkg package description, can be path or package name
    #' @param fields fields to get & report dependencies for
    #' @note R and the R version is NOT added to \code{Depends}
    #' @examples
    #' add_pkg_versions("qmethod")
    #' add_pkg_versions("MASS")
    #' \dontrun { # assumes you're in a pkg devel dir
    #' add_pkg_versions()
    #' }
    add_pkg_versions <- function(pkg=".",
                                 fields=c("Depends", "Imports", "LinkingTo", "Suggests")) {
    
      require(purrr)
      walk(c("dplyr", "tools", "stringi", "devtools"), require, character.only=TRUE)
    
      stopifnot(is_scalar_character(pkg), pkg != "")
      fields <- match.arg(fields, c("Depends", "Imports", "LinkingTo", "Suggests"),
                          several.ok=TRUE)
    
      avail <- as_data_frame(available.packages())
    
      if (pkg == ".") {
        pkg_deps <- unclass(as_data_frame(read.dcf(file.path(package_file(), "DESCRIPTION"))))
        pkg <- pkg_deps$Package
        map(fields, ~stri_split_lines(pkg_deps[[.]])) %>%
          map(function(x) {
            if (length(x) > 0) {
              unlist(x) %>%
                stri_replace_all_regex(" \\(.*$|,", "") %>%
                discard(`%in%`, c("", "R"))
            } else { x }
          }) -> pkg_deps
        names(pkg_deps) <- fields
      } else {
        pkg_deps <- map(fields, ~flatten_chr((package_dependencies(pkg,  which=.))))
        names(pkg_deps) <- fields
      }
    
      pkg_deps <- discard(pkg_deps, function(x) {length(x)==0})
    
      map(pkg_deps, function(x) {
    
        non_base <- filter(avail, Package %in% x)
        base <- setdiff(x, non_base$Package)
    
        non_base %>%
          mutate(pv=sprintf("%s (>= %s)", Package, Version)) %>%
          select(pv) %>%
          flatten_chr() -> pkg_plus_version
    
        sort(c(pkg_plus_version, base))
    
      }) -> pkg_deps
    
      cat("Package: ", pkg, "\n", sep="")
      walk(names(pkg_deps), function(x) {
    
        cat(x, ":\n", sep="")
        sprintf("    %s", pkg_deps[[x]]) %>%
          paste0(collapse=",\n") %>%
          cat()
        cat("\n")
    
      })
    
    }
    

    One of your packages:

    add_pkg_versions("qmethod")
    
    Package: qmethod
    Imports:
        digest (>= 0.6.10),
        GPArotation (>= 2014.11-1),
        knitr (>= 1.13),
        methods,
        psych (>= 1.6.6),
        tools,
        xtable (>= 1.8-2)
    

    Just to show edge cases are handled:

    add_pkg_versions("MASS")
    
    Package: MASS
    Depends:
        graphics,
        grDevices,
        stats,
        utils
    Imports:
        methods
    Suggests:
        lattice (>= 0.20-33),
        nlme (>= 3.1-128),
        nnet (>= 7.3-12),
        survival (>= 2.39-5)