r - 本地存储库中的 RStudio Connect、Packrat 和自定义包
问题描述
我们最近在我的办公室安装了 RStudio Connect。对于我们的工作,我们制作了自定义包,我们通过打开项目和构建+重新加载在自己之间进行了更新。
我知道我可以让我们的自定义包在带有 RSConnect 的应用程序中工作的唯一方法是建立一个本地 repo 并设置我们options(repos)
的包含它。
目前我有以下内容:
library(drat)
RepoAddress <- "C:/<RepoPath>" # High level path
drat::insertPackage(<sourcePackagePath>, repodir = RepoAddress)
# Add this new repo to Rs knowledge of repos.
options(repos = c(options("repos")$repos,LocalCurrent = paste0("file:",RepoAddress)))
# Install <PackageName> from the local repo :)
install.packages("<PackageName>")
目前这很好用,我可以从本地 repo 安装我的自定义包。这向我表明本地存储库已正确设置。
另外,我已将DESCRIPTION
文件更改为多出一行repository:LocalCurrent
.
但是,当我尝试部署引用的 Shiny 应用程序或 Rmd 时,我在部署时收到以下错误:
Error in findLocalRepoForPkg(pkg, repos, fatal = fatal) :
No package '<PackageName> 'found in local repositories specified
我知道这是packrat
在部署过程中无法找到我的本地存储库的问题(我相信在它使用的阶段packrat::snapshot()
)。这很令人困惑,因为我本以为packrat
会使用option("repos")
类似于install.packages
. 如果我遵循这些功能,我可以看到特定的失败点是packrat:::findLocalRepoForPkg("<PackageName", repos = packrat::get_opts("local.repos"))
,即使在我定义之后它也会失败packrat::set_opts("local.repos" = c(CurrentRepo2 = paste0("file:",RepoAddress)))
如果我深入packrat:::findLocalRepoForPkg
研究,它会失败,因为它找不到名为:“C://”的文件/文件夹。我原以为这肯定会失败,因为 repos 遵循 C://bin/windows/contrib/3.3/ 结构。回购协议在任何时候都不会具有它正在寻找的结构吗?
我认为这最后一部分表明我在本质上误解了一些东西。任何有关配置我的 repo 的指导packrat
都可以理解它会很棒。
解决方案
应始终检查 RStudio connect 目前支持哪些选项: https ://docs.rstudio.com/connect/admin/r/package-management/#private-packages
就我个人而言,我不喜欢包含本地/私有包的所有选项,因为它违背了部署闪亮应用程序的简单目标的目的。在许多情况下,我不能只在组织中设置本地存储库,因为我没有权限。我必须给 IT 支持发送电子邮件以让他们手动安装新软件包也很不方便。总的来说,我认为 RS connect 是一个很棒的产品,因为它很简单,但是当涉及到本地包时,它真的不是。
我找到了 Rstudio 官方推荐的一个不错的替代方案/Hack。我想thise也可以与shinyapps.io一起使用,但我还没有尝试过。解决方案如下:
添加到 global.R if(!require(local_package) ) devtools::load_all("./local_package")
编写一个复制所有源文件的脚本,这样您就可以得到一个带有本地包源目录的闪亮应用程序,您可以调用该目录,
./inst/shinyconnect/
或者将本地包复制到./inst/shinyconnect/local_package
清单中。将脚本添加
./shinyconnect/packrat_sees_these_dependencies.R
到闪亮文件夹,这将由 packrat-manifest 拾取破解 rsconnet/packrat 以在构建时忽略特定命名的包
(1)
#start of global.R...
#load more packages for shiny
library(devtools) #need for load_all
library(shiny)
library(htmltools) #or what ever you need
#load already built local_package or for shiny connection pseudo-build on-the-fly and load
if(!require(local_package)) {
#if local_package here, just build on 2 sec with devtools::load_all()
if(file.exists("./DESCRIPTION")) load_all(".") #for local test on PC/Mac, where the shinyapp is inside the local_package
if(file.exists("./local_package/DESCRIPTION")) load_all("./local_package/") #for shiny conenct where local_package is inside shinyapp
}
library(local_package) #now local_package must load
(3)
make script 加载你本地包的所有依赖。Packrat 会看到这一点。该脚本永远不会被实际执行。把它放在./shinyconnect/packrat_sees_these_dependencies.R
#these codelines will be recognized by packrat and package will be added to manifest
library(randomForest)
library(MASS)
library(whateverpackageyouneed)
(4)在部署期间,清单生成器 (packrat) 将忽略任何命名的 local_package 的存在。这是 packrat 中的一个选项,但 rsconnect 不公开此选项。一个技巧是将 rsconnect 加载到内存并修改 sub-sub-sub-functionperformPackratSnapshot()
以允许这样做。在下面的脚本中,我这样做并部署了一个闪亮的应用程序。
library(rsconnect)
orig_fun = getFromNamespace("performPackratSnapshot", pos="package:rsconnect")
#packages you want include manually, and packrat to ignore
ignored_packages = c("local_package")
#highjack rsconnect
local({
assignInNamespace("performPackratSnapshot",value = function (bundleDir) {
owd <- getwd()
on.exit(setwd(owd), add = TRUE)
setwd(bundleDir)
srp <- packrat::opts$snapshot.recommended.packages()
packrat::opts$snapshot.recommended.packages(TRUE, persist = FALSE)
packrat::opts$ignored.packages(get("ignored_packages",envir = .GlobalEnv)) #ignoreing packages mentioned here
print("ignoring following packages")
print(get("ignored_packages",envir = .GlobalEnv))
on.exit(packrat::opts$snapshot.recommended.packages(srp,persist = FALSE), add = TRUE)
packages <- c("BiocManager", "BiocInstaller")
for (package in packages) {
if (length(find.package(package, quiet = TRUE))) {
requireNamespace(package, quietly = TRUE)
break
}
}
suppressMessages(packrat::.snapshotImpl(project = bundleDir,
snapshot.sources = FALSE, fallback.ok = TRUE, verbose = FALSE,
implicit.packrat.dependency = FALSE))
TRUE
},
pos = "package:rsconnect"
)},
envir = as.environment("package:rsconnect")
)
new_fun = getFromNamespace("performPackratSnapshot", pos="package:rsconnect")
rsconnect::deployApp(appDir="./inst/shinyconnect/",appName ="shinyapp_name",logLevel = "verbose",forceUpdate = TRUE)
推荐阅读
- amazon-web-services - 无法使用 react-native-xmpp 连接到 Ejabberd 服务器
- clojure - 一种在嵌套地图中重塑/连接/展平数据的声明性方式
- angular - ValueChanges 为组件中的 formControls 发出,但不为子组件中的 formControl 发出?
- spring-boot - 使用 Spring-Boot 2.3.3 H2 内存数据库抛出 NonTransientConnectionException
- model - Vowpal Wabbit 模型加载
- django - 尝试使用 UpdateAPIView 进行部分更新时出现错误请求 400
- c# - ASP Net core - 如何实现后台服务本地化?
- python - Django 3.1:OperationalError - 没有这样的列/表
- npm - 无法解决我的 npm install 问题
- swup - Swup JS 卡在“pageLoaded”状态