[英]List all the packages required in a script assuming package::function() in R
Let´s assume that all the non-base R functions in a script are called by package::function()
.假设脚本中的所有非基础 R 函数都由
package::function()
调用。 Therefore, it don´t have any full package load during the script run.因此,它在脚本运行期间没有任何完整的包加载。 Let´s assume that we have the a R script called
run.R
with the following contents.假设我们有一个名为
run.R
的 R 脚本, run.R
包含以下内容。
"data.table::fread(file)"
In this example, the script would need the data.table
package.在这个例子中,脚本需要
data.table
包。 I am looking for a R function that reading this external run.R
script would give the code to install all the requested packages ie:我正在寻找一个 R 函数,它读取这个外部
run.R
脚本会给安装所有请求的包的代码,即:
install.packages("data.table")
Any idea about existent functions or strategies?关于现有功能或策略的任何想法?
You could try something like this using regex:您可以使用正则表达式尝试类似的操作:
f <- file("/path/to/here/file.R") # set up connection to file
file_lines <- readLines(con = f) # read file into list
close(f)
pckgs <- lapply(file_lines, function(l) {
if(grepl("::", l)){
gsub(".*?([[:alnum:]\\.]+)::.*","\\1", l)
} else {
return(NULL)
}
})
unique(unlist(pckgs))
I worked under the assumption that package names only contains letters and numbers.我的工作假设包名只包含字母和数字。 you may need to change the regex pattern if that isn't the case.
如果不是这种情况,您可能需要更改正则表达式模式。
Update: changed the assumption to include a .
更新:将假设更改为包含
.
as per the data.table
example根据
data.table
示例
The other solutions using regular expressions will also match ::
if it occurs in a comment or string literal.使用正则表达式的其他解决方案也将匹配
::
如果它出现在注释或字符串文字中。 It's better to parse the script and look for things that parse to the pkg::fn
operation.最好解析脚本并查找解析为
pkg::fn
操作的内容。 For example:例如:
src <- "data.table::fread(file)"
# Use src <- readLines("source.R") in the real case, or parse the file directly
parsed <- parse(text = src)
parseData <- getParseData(parsed)
parseData$text[parseData$token == "SYMBOL_PACKAGE"]
#> [1] "data.table"
Edited to add: You can put this in a function to install necessary packages before running a script.编辑添加:您可以将其放入一个函数中,以便在运行脚本之前安装必要的软件包。 For example, if these lines are in
~/temp/run.R
:例如,如果这些行在
~/temp/run.R
:
file <- "not::a::package"
data.table::fread(file)
foobar::notafunction()
then you get these results:然后你会得到这些结果:
installThenSource <- function(file, ...) {
parsed <- parse(file)
parseData <- getParseData(parsed)
packages <- unique(parseData$text[parseData$token == "SYMBOL_PACKAGE"])
for (p in packages) {
if (!requireNamespace(p, quietly = TRUE)) {
message("Installing ", p)
install.packages(p)
if (!requireNamespace(p, quietly = TRUE))
stop("Install of ", p, " failed.")
} else
message("Package ", p, " already installed.")
}
source(file, ...)
}
installThenSource("~/temp/run.R")
#> Package data.table already installed.
#> Installing foobar
#> Warning: package 'foobar' is not available (for R version 3.6.1)
#> Error in installThenSource("~/temp/run.R"): Install of foobar failed.
Here is a function that finds strings like package::function
.这是一个查找类似
package::function
字符串的package::function
。
findPackages <- function(file){
txt <- readLines(file)
inx <- grep('::', txt)
txt <- txt[inx]
m <- regexpr('[[:alnum:]]+::', txt)
pkg <- regmatches(txt, m)
unique(sub('::', '', pkg))
}
This Ubuntu bash command gets all files *.R
in the working directory with ::
in them.这个 Ubuntu bash 命令获取工作目录中所有带有
::
文件*.R
。
fls <- system2('grep', args = c('-l', '::', '*.R'), stdout = TRUE)
Now apply the function to a file that calls functions like that.现在将该函数应用到一个调用类似函数的文件。
findPackages(fls[1])
And to all such files found with the bash command.以及使用 bash 命令找到的所有此类文件。
pkgs <- lapply(fls, findPackages)
unique(unlist(pkgs))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.