Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@ jobs:
r-version: ${{ matrix.config.r }}
http-user-agent: ${{ matrix.config.http-user-agent }}

- name: Install Linux system libraries
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libcairo2-dev \
libfribidi-dev \
libfontconfig1-dev \
libfreetype6-dev \
libharfbuzz-dev \
libjpeg-dev \
libpng-dev \
libtiff5-dev \
libwebp-dev \
pkg-config

- name: Configure Linux Makevars for gdtools
if: runner.os == 'Linux'
run: |
mkdir -p ~/.R
cat <<EOF >> ~/.R/Makevars
CPPFLAGS=$(pkg-config --cflags cairo freetype2 fontconfig)
LDFLAGS=$(pkg-config --libs-only-L cairo freetype2 fontconfig)
LDLIBS=$(pkg-config --libs-only-l cairo freetype2 fontconfig)
EOF

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
Expand Down
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ Imports:
stringr,
zip,
here,
fs
fs,
usethis
Config/roxygen2/version: 8.0.0
Suggests:
testthat (>= 3.0.0)
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export(arrangeCdmNames)
export(assertCdmNames)
export(createResultsDir)
export(getPkgZips)
export(insertStructure)
export(setLoggers)
export(unZipStudyFiles)
export(zipStudyFiles)
Expand Down
230 changes: 230 additions & 0 deletions R/insertStructure.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#' Install default package bundle
#'
#' Installs a predefined set of DARWIN EU®/OHDSI packages into the study project
#' and updates their dependencies. The standard package list includes the packages
#' omopgenerics, PhenotypeR, DrugExposureDiagnostics, CohortConstructor,
#' IncidencePrevalence, DrugUtilisation, CohortCharacteristics, CohortSurvival,
#' visOmopResults and DarwinShinyModules.
#'
#' @return
#' An invisible list of the installed packages.
installPackageBundle <- function(path) {

# Install default package bundle
complete_darwin <- list(
cran = c(
"omopgenerics",
"PhenotypeR",
"DrugExposureDiagnostics",
"CohortConstructor",
"IncidencePrevalence",
"DrugUtilisation",
"CohortCharacteristics",
"CohortSurvival",
"visOmopResults"
),
github = c(
"darwin-eu/DarwinShinyModules"
)
)

if (!dir.exists(file.path(path, "renv"))) {
cli::cli_abort(
message = c(
"x" = "No renv detected in {.path {path}}.",
"i" = "Need to initialize the environment with {.fn renv::init} first."
)
)
}

# withr::with_dir(path, {
# Install packages with renv
renv::install(
packages = complete_darwin$cran,
project = path
)
renv::install(
packages = complete_darwin$github,
project = path
)

# Add dependencies (default type = "Imports")
pkg_names <- c(
complete_darwin$cran,
basename(complete_darwin$github)
)

if (!requireNamespace("usethis", quietly = TRUE)) {
cli::cli_inform(
"Installing required package: 'usethis'"
)
renv::install(
packages = "usethis",
project = path
)
}

for (pkg in pkg_names) {
usethis::use_package(pkg)
}

# Update lockfile
renv::snapshot(
project = path
)
# })

# Return invisible package list
invisible(pkg_names)

}


#' Insert default documentation files
#'
#' Creates default `NEWS.md`, `README.Rmd` and `LICENSE.md` (Apache License 2.0) files.
#'
#' @return
#' No return value.
insertDocs <- function(path) {
withr::with_dir(path, {
usethis::use_news_md(open = FALSE)
usethis::use_readme_rmd(open = FALSE)
usethis::use_apl2_license()
})
}


#' Insert default study files
#'
#' Creates the `inst` and `extras` folders and populates the `R` folder with
#' ready files for standard study functions.
#'
#' @param path Character string identifying the path to the study project,
#' default `"."`.
#' @param n_obj Number of study objectives, default `n_obj = 3`.
#'
#' @return
#' No return value.
insertStudyFiles <- function(
path = ".",
n_obj = 3
) {
# R/
if ("hello.R" %in% list.files(file.path(path, "R"))) {
unlink(file.path(path, "R/hello.R"))
}
usethis::use_r("createCohorts", open = FALSE)
usethis::use_r("runStudy", open = FALSE)
usethis::use_r("runDiagnostics", open = FALSE)
usethis::use_r("pullFromAtlas", open = FALSE)
usethis::use_r("utils", open = FALSE)
usethis::use_r("globals", open = FALSE)
usethis::use_r("merge", open = FALSE)
for (i in 1:n_obj) {
usethis::use_r(paste0("objective", i), open = FALSE)
}
# man/
if (!dir.exists(file.path(path, "man"))) {
dir.create(file.path(path, "man"))
}
if ("hello.Rd" %in% list.files(file.path(path, "man"))) {
unlink(file.path(path, "man/hello.Rd"))
}
# inst/
dir.create(file.path(path, "inst"))
dir.create(file.path(path, "inst/cohorts"))
dir.create(file.path(path, "inst/concept_sets"))
# extras/
dir.create(file.path(path, "extras"))
invisible(file.create(file.path(path, "extras/CodeToRun.R")))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a later iteration probably we can plug the actual file with some empty basic functions.

invisible(file.create(file.path(path, "extras/pullCohortsFromAtlas.R")))
}


#' Insert default test files
#'
#' Creates the `tests` folder and populates the `tests/testthat` folder with
#' a default test file for each script found in the `R` folder.
#'
#' @param path Character string identifying the path to the study project,
#' default `"."`.
#'
#' @return
#' No return value.
insertTests <- function(
path = "."
) {

usethis::use_testthat()

if (!dir.exists(file.path(path, "R")) | length(list.files(file.path(path, "R"))) == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this check is good. Also valuable if this function is exported and we could run this functions separately. But maybe in insert structure, there could be a check that we have R/objective files before actually running this function so it is more clear if there's an error. But for this iteration I think is good.

cli::cli_abort(
message = c(
"!" = "No .R files are found to generate tests",
"x" = "The R folder in current project doesn't exist or is empty."
)
)
}

# Create test files for each script in R/ except globals.R
for (script in list.files(file.path(path, "R"))) {
if (script == "globals.R") {
next
} else{ # remove ".R"
usethis::use_test(substr(script, 1, nchar(script) -2), open = FALSE)
}
}
}


#' Set up study structure
#'
#' Creates the standard structure required for a new OMOP study package.
#' It includes standard folders, R scripts, test and documentation files and it
#' installs a default list of DARWIN EU®/OHDSI packages.
#'
#' It assumes an active R project has already been created and the `renv`
#' initialized.
#'
#' @param path Character string identifying the path to the study project,
#' default `"."`.
#' @param n_obj Number of study objectives, default `n_obj = 3`.
#'
#' @return
#' No return value.
#'
#' @export
insertStructure <- function(
path = ".",
n_obj = 3
) {

# Need an existing package to run the function
if (!file.exists(file.path(path, "DESCRIPTION"))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably for a next iteration we can put a check like some of the functions in usethis that detect if the location provided is at the project/package level.

cli::cli_abort(
message = c(
"!" = "The path doesn't correspond to a package folder.",
"x" = "A package must contain a DESCRIPTION file. No DESCRIPTION detected at {.path {path}}.",
"i" = "Create a package first with {.fn usethis::create_package} or through the RStudio interface."
)
)
}

# Set up structure at specified project path
cli::cli_h1("Setting up study package structure")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cli structure, is very clean


cli::cli_alert_info("Installing package bundle...")
installPackageBundle(path)

cli::cli_alert_info("Inserting documentation files...")
insertDocs(path)

cli::cli_alert_info("Inserting study files...")
insertStudyFiles(path, n_obj)

cli::cli_alert_info("Inserting test files...")
insertTests(path)

cli::cli_alert_success("Package structure created successfully.")
}
74 changes: 74 additions & 0 deletions docs/404.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions docs/404.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Content not found. Please use links in the navbar.

# Page not found (404)
Loading
Loading