Nothing
#' Generate Singularity Definition File
#'
#' @description
#' Generate a Singularity/Apptainer definition file for HPC environments.
#' Singularity is commonly used in HPC clusters where Docker is not available.
#'
#' @param output_dir Character. Directory to save Singularity files (required).
#' @param r_version Character. R version to use. Default is current R version.
#' @param base_image Character. Base Docker image. Default "rocker/r-ver"
#' @param conda_env Character. Path to conda environment file. Optional.
#' @param system_deps Character vector. System dependencies to install
#' @param project_name Character. Name for the project
#'
#' @return List of generated file paths
#'
#' @export
#'
#' @examples
#' \dontrun{
#' generate_singularity(
#' output_dir = tempdir(),
#' project_name = "my_analysis",
#' system_deps = c("samtools", "bwa")
#' )
#' }
generate_singularity <- function(
output_dir,
r_version = NULL,
base_image = "rocker/r-ver",
conda_env = NULL,
system_deps = NULL,
project_name = "reproflow-project") {
if (is.null(r_version)) {
r_version <- paste(R.version$major, R.version$minor, sep = ".")
}
# Create output directory
dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
cli::cli_alert_info("Generating Singularity definition file...")
# Build definition file
def_lines <- c(
"Bootstrap: docker",
paste0("From: ", base_image, ":", r_version),
"",
"%labels",
paste0(" PROJECT ", project_name),
paste0(" R_VERSION ", r_version),
" GENERATED_BY Capsule",
"",
"%help",
paste0(" Reproducible R environment for: ", project_name),
paste0(" R version: ", r_version),
" Generated by Capsule package",
"",
"%post",
" # Update package lists",
" apt-get update -y",
"",
" # Install essential build tools",
" apt-get install -y \\",
" wget \\",
" ca-certificates \\",
" git \\",
" libcurl4-openssl-dev \\",
" libssl-dev \\",
" libxml2-dev"
)
# Add system dependencies
if (!is.null(system_deps) && length(system_deps) > 0) {
def_lines <- c(def_lines, "")
def_lines <- c(def_lines, " # Install additional system dependencies")
for (dep in system_deps) {
def_lines <- c(def_lines, paste0(" apt-get install -y ", dep))
}
}
def_lines <- c(
def_lines,
"",
" # Clean up",
" apt-get clean",
" rm -rf /var/lib/apt/lists/*",
""
)
# Conda installation if needed
if (!is.null(conda_env) && file.exists(conda_env)) {
def_lines <- c(
def_lines,
" # Install Miniconda",
" cd /opt",
" wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh",
" bash Miniconda3-latest-Linux-x86_64.sh -b -p /opt/conda",
" rm Miniconda3-latest-Linux-x86_64.sh",
"",
" # Add conda to PATH",
" export PATH=/opt/conda/bin:$PATH",
" conda init bash",
"",
paste0(" # Restore conda environment from ", basename(conda_env)),
paste0(" conda env create -f /project/", basename(conda_env)),
""
)
}
# R packages via renv
def_lines <- c(
def_lines,
" # Install renv for R package management",
" R -e \"install.packages('renv', repos='https://cloud.r-project.org/')\"",
""
)
# Files section
def_lines <- c(
def_lines,
"%files",
" # Copy project files (adjust as needed)",
" renv.lock /project/renv.lock"
)
if (!is.null(conda_env) && file.exists(conda_env)) {
def_lines <- c(
def_lines,
paste0(" ", conda_env, " /project/", basename(conda_env))
)
}
def_lines <- c(def_lines, "")
# Environment section
def_lines <- c(
def_lines,
"%environment",
" export LC_ALL=C",
" export PATH=/opt/R/bin:$PATH"
)
if (!is.null(conda_env)) {
def_lines <- c(
def_lines,
" export PATH=/opt/conda/bin:$PATH"
)
}
def_lines <- c(
def_lines,
"",
"%runscript",
" # Default: launch R",
" cd /project",
" exec R \"$@\""
)
# Write definition file
def_file <- file.path(output_dir, paste0(project_name, ".def"))
writeLines(def_lines, def_file)
cli::cli_alert_success("Definition file created: {.file {def_file}}")
# Create build script
build_script <- c(
"#!/bin/bash",
"# Build Singularity/Apptainer container",
"",
paste0("singularity build ", project_name, ".sif ", project_name, ".def"),
"",
"# If singularity is not available, try apptainer",
"# apptainer build ", project_name, ".sif ", project_name, ".def"
)
build_file <- file.path(output_dir, "build_singularity.sh")
writeLines(build_script, build_file)
Sys.chmod(build_file, mode = "0755")
cli::cli_alert_success("Build script created: {.file {build_file}}")
# Create usage README
readme_lines <- c(
paste("#", "Singularity Container for", project_name),
"",
"## Building the Container",
"",
"```bash",
paste0("sudo singularity build ", project_name, ".sif ", project_name, ".def"),
"```",
"",
"Or use the provided script:",
"```bash",
"sudo bash build_singularity.sh",
"```",
"",
"**Note:** Building requires sudo/root privileges.",
"",
"## Running the Container",
"",
"### Interactive R session",
"```bash",
paste0("singularity shell ", project_name, ".sif"),
"```",
"",
"### Execute R script",
"```bash",
paste0("singularity exec ", project_name, ".sif Rscript your_script.R"),
"```",
"",
"### Bind mount your data directory",
"```bash",
paste0("singularity exec --bind /path/to/data:/data ", project_name, ".sif Rscript analysis.R"),
"```",
"",
"## HPC Usage",
"",
"Most HPC systems support Singularity. Example SLURM job:",
"",
"```bash",
"#!/bin/bash",
"#SBATCH --job-name=reproflow",
"#SBATCH --ntasks=1",
"#SBATCH --cpus-per-task=4",
"#SBATCH --mem=16G",
"",
paste0("singularity exec ", project_name, ".sif Rscript analysis.R"),
"```",
"",
"## Apptainer",
"",
"Singularity has been renamed to Apptainer. The commands are identical:",
"```bash",
paste0("apptainer build ", project_name, ".sif ", project_name, ".def"),
paste0("apptainer exec ", project_name, ".sif Rscript analysis.R"),
"```"
)
readme_file <- file.path(output_dir, "SINGULARITY_README.md")
writeLines(readme_lines, readme_file)
cli::cli_alert_success("README created: {.file {readme_file}}")
cli::cli_alert_success("Singularity configuration complete!")
cli::cli_h2("Next steps:")
cli::cli_ul(c(
paste("Build container: sudo bash", build_file),
paste("Run container: singularity exec", project_name, ".sif R")
))
invisible(list(
definition = def_file,
build_script = build_file,
readme = readme_file
))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.