2016-07-31 75 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 
} 
相關問題