T.H*_*lme 5 r local package shiny-server packrat
我们最近在我的办公室安装了 RStudio Connect。对于我们的工作,我们制作了自定义包,我们通过打开项目并构建+重新加载在我们之间进行了更新。
据我所知,让我们的自定义包在具有 RSConnect 的应用程序中工作的唯一方法是获取本地存储库并将其设置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>")
Run Code Online (Sandbox Code Playgroud)
目前这工作得很好,我可以从本地存储库安装我的自定义包。这向我表明本地存储库设置正确。
另外,我已更改DESCRIPTION文件以添加一行额外的内容repository:LocalCurrent:
但是,当我尝试部署引用的 Shiny 应用程序或 Rmd 时,我在部署时收到以下错误:
Error in findLocalRepoForPkg(pkg, repos, fatal = fatal) :
No package '<PackageName> 'found in local repositories specified
Run Code Online (Sandbox Code Playgroud)
我知道这是在部署过程中无法找到我的本地存储库的问题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://”的文件/文件夹。我本以为这肯定会失败,因为存储库遵循 C://bin/windows/contrib/3.3/ 结构。回购协议在任何时候都不会具有它正在寻找的结构吗?
我认为最后一部分表明我严重误解了某些事情。任何有关配置我的存储库以便packrat能够理解的指导都会很棒。
人们应该始终检查 RStudio connect 目前支持哪些选项: https://docs.rstudio.com/connect/admin/r/package-management/#private-packages
就我个人而言,我不喜欢包含本地/私有包的所有选项,因为它违背了部署闪亮应用程序的简单目标的目的。在许多情况下,我不能只在组织中建立本地存储库,因为我没有权限。我还必须向 IT 支持人员发送电子邮件,让他们手动安装新软件包,这也很不方便。总的来说,我认为 RS connect 是很棒的产品,因为它很简单,但当涉及到本地软件包时,事实并非如此。
我找到了一个不错的替代方案/Hack to Rstudio 官方推荐。我想这也可以与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
Run Code Online (Sandbox Code Playgroud)
(3)
让脚本加载本地包的所有依赖项。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)
Run Code Online (Sandbox Code Playgroud)
(4)在部署期间,清单生成器 (packrat) 将忽略任何命名的 local_package 的存在。这是 packrat 中的一个选项,但 rsconnect 不公开此选项。一种破解方法是将 rsconnect 加载到内存并修改 sub-sub-sub 函数performPackratSnapshot()以允许此操作。在下面的脚本中,我这样做并部署了一个闪亮的应用程序。
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, verbose = FALSE) {
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)
Run Code Online (Sandbox Code Playgroud)
问题之一是命名法。
我已经建立了一个 CRAN 意义上的仓库。它工作正常并且没问题。当packrat引用 a时local repo,它指的是本地 git 风格的存储库。
这解决了为什么 findlocalrepoforpkg 看起来不起作用 - 它被设计为与不同类型的存储库一起使用。