2016-07-31 72 views
5

我是软件包开发人员,并且想要说明在DESCRIPTION文件中使用我的软件包所需的最低R版本。因为Imports和Depends字段是以逗号分隔的文本,有时包含的软件包有版本要求,所以结果不容易(通过机器可读)查找递归依赖关系。确定所有软件包相关性的最小R版本

解决方案中描述的: Listing R Package Dependencies Without Installing Packages不是递归解决方案。如果嵌套的依赖关系需要R> 3.3,我想知道它。

至少,我希望看到R的最低版本以及给定CRAN软件包的导入,链接和依赖软件包。更好的办法是列出设置最小R或软件包版本的软件包或软件包。通过消除具有更高版本要求的依赖关系,我可以为更多的人提供他们无法修复的机构旧R版本:有些仍然在R 2.x上。基于从@hrbrmstr的想法,并与基函数写

+0

我怀疑你将在这个项目招募极大的兴趣,但一个方法可能是首先检查R版本的日期,然后不安装任何具有更新日期的软件包。 (它不会是一个R脚本。)您需要确保适用于特定版本的R和特定操作系统的构建工具可用,因为没有全面的二进制包存储。另一种可能是确定使用者落后的原因并解决这些问题。 –

+1

对引用问题的第二个答案确实提供了递归解决方案。所以也许这是重复的(即使检查标记的解决方案完全令人满意)?我将认为标记是重复的,但可能会这样做,除非编辑问题以包含更完整的需求描述。 –

+1

不幸的是,这充满了潜在的危险。你有像[rodham'](https://cran.rstudio.com/web/packages/rodham/)这样的软件包,它的_claim_> = 2.1.0,但是_actually_ needs> = 3.2.0,因为使用了函数('trimws()')在3.2.0中引入,并且在2.1.0中不可用。由于在3.2.0版本发布之后它被引入到CRAN中,并且CRAN测试仅适用于当前版本和devel版本,因此它将错过这种依赖性错误。我怀疑你最好用每个R版本构建一组docker镜像,并对它们运行pkg测试来确定最小版本。非常自动化。 – hrbrmstr

回答

4
min_r_version <- function(package="ggplot2", exclude_main_pkg=TRUE) { 

    purrr::walk(c("tools", "purrr", "devtools", "stringi", "tidyr", "dplyr"), 
       require, character.only=TRUE) 

    deps <- package_dependencies(package, recursive=TRUE) 

    if (exclude_main_pkg) { 
    pkgs <- deps[[1]] 
    } else { 
    pkgs <- c(package, deps[[1]]) 
    } 

    available.packages() %>% 
    as_data_frame() %>% 
    filter(Package %in% pkgs) %>% 
    select(Depends) %>% 
    unlist() -> pkg_list 

    # if main pkg only relied on core R packages (i.e. pkgs that aren't in CRAN) and we 
    # excluded the pkg itself from the min version calculation, this is an edge case we need 
    # to handle. 

    if (length(pkg_list) == 0) return("Unspecified") 

    stri_split_regex(pkg_list, "[,]") %>% 
    unlist() %>% 
    trimws() %>% 
    stri_match_all_regex(c("^R$|^R \\(.*\\)$")) %>% 
    unlist() %>% 
    discard(is.na(.)) %>% 
    unique() %>% 
    stri_replace_all_regex("[R >=\\(\\)]", "") %>% 
    data_frame(vs=.) %>% 
    separate(vs, c("a", "b", "c"), fill="right") %>% 
    mutate(c=ifelse(is.na(c), 0, c)) %>% 
    arrange(a, b, c) %>% 
    tail(1) %>% 
    unite(min, a:c, sep=".") -> vs 

    return(vs$min) 

} 

# did we handle the edge cases well enought? 
base <- c("base", "compiler", "datasets", "grDevices", "graphics", "grid", "methods", "parallel", "profile", "splines", "stats", "stats4", "tcltk", "tools", "translations") 
(base_reqs <- purrr::map_chr(base, min_r_version)) 
## [1] "Unspecified" "Unspecified" "Unspecified" "Unspecified" "Unspecified" 
## [6] "Unspecified" "Unspecified" "Unspecified" "Unspecified" "Unspecified" 
## [11] "Unspecified" "Unspecified" "Unspecified" "Unspecified" "Unspecified" 

# a few of the "core" contributed pkgs rely on a pkg or two outside of base 
# but many only rely on base packages, to this is another gd edge case to 
# text for. 
contrib <- c("KernSmooth", "MASS", "Matrix", "boot", "class", "cluster", "codetools", "foreign", "lattice", "mgcv", "nlme", "nnet", "rpart", "spatial", "survival") 
contrib_reqs <- purrr::map_chr(contrib, min_r_version) 
## [1] "Unspecified" "Unspecified" "3.0.0"  "Unspecified" "3.1.0"  
## [6] "Unspecified" "Unspecified" "Unspecified" "Unspecified" "3.0.2"  
## [11] "3.0.0"  "Unspecified" "Unspecified" "Unspecified" "3.0.1"  

# See what the min version of R shld be for some of my pkgs 
min_r_version("ggalt") # I claim R (>= 3.0.0) in DESCRIPTION 
## [1] "3.1.2" 

min_r_version("curlconverter") # I claim R (>= 3.0.0) in DESCRIPTION 
## [1] "3.1.2" 

min_r_version("iptools") # I claim R (>= 3.0.0) in DESCRIPTION 
## [1] "3.0.0" 
+0

哇。万分感谢。这是否排除了查询包本身的R要求,因为这是我们想要更改的变量? –

+0

现在,它包括它,因为如果我们排除它,需要一些'if-else'逻辑来处理某些边缘情况,但这是该过程的核心逻辑。 – hrbrmstr

+1

更新后的函数支持排除指定的pkg并处理所述的边界情况。可能还有其他边缘情况,我没有想到。 – hrbrmstr

0

,我现在使用下面的功能:

min_r_version <- function(pkg) { 
    requireNamespace("tools") 
    requireNamespace("utils") 
    avail <- utils::available.packages(utils::contrib.url(repo)) 
    deps <- tools::package_dependencies(pkg, db = avail, recursive = TRUE) 
    if (is.null(deps)) 
    stop("package not found") 

    pkgs <- deps[[1]] 
    repo = getOption("repo") 
    if (is.null(repo)) 
    repo <- "https://cloud.r-project.org" 

    matches <- avail[ , "Package"] %in% pkgs 
    pkg_list <- avail[matches, "Depends"] 
    vers <- grep("^R$|^R \\(.*\\)$", pkg_list, value = TRUE) 
    vers <- gsub("[^0-9.]", "", vers) 
    if (length(vers) == 0) 
    return("Not specified") 

    max_ver = vers[1] 
    if (length(vers) == 1) 
    return(max_ver) 

    for (v in 2:length(vers)) 
    if (utils::compareVersion(vers[v], max_ver) > 0) 
     max_ver <- vers[v] 

    max_ver 
} 
相关问题