diff --git a/01_deploy_via_Docker.sh b/01_deploy_via_Docker.sh new file mode 100644 index 0000000..2146cc0 --- /dev/null +++ b/01_deploy_via_Docker.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +source scripts/colored_print.sh +source scripts/check_and_set_email_credentials.sh +source scripts/check_CPU_number.sh +set -e + +#################### 1 email +print_green "1. Configurations of email to send results" +check_and_set_email_credentials + +#################### 2. CPU +print_green "2. Configuration of CPU number" +check_cpu_number + +#################### 3. Docker build +print_green "3. Docker building" +chmod 777 logs result +docker-compose up -d diff --git a/deploy_one_bash.sh b/01_deploy_via_bash.sh similarity index 100% rename from deploy_one_bash.sh rename to 01_deploy_via_bash.sh diff --git a/R/R_packages_installation.log b/R/R_packages_installation.log new file mode 100644 index 0000000..cb815f9 --- /dev/null +++ b/R/R_packages_installation.log @@ -0,0 +1,46 @@ +[1] TRUE +[1] TRUE +[1] TRUE +character(0) + +The installed packages are as follows: + [1] "av" "bslib" + [3] "daattali/shinycssloaders" "daattali/shinydisconnect" + [5] "data.table" "datawookie/emayili" + [7] "devtools" "dplyr" + [9] "dreamRs/shinybusy" "dreamRs/shinyWidgets" +[11] "DT" "emayili" +[13] "enrichplot" "future" +[15] "gapminder" "ggasym" +[17] "ggplot2" "ggpubr" +[19] "glue" "Hmisc" +[21] "httpuv" "jhrcook/ggasym" +[23] "kableExtra" "magick" +[25] "merlinoa/shinyFeedback" "msigdbr" +[27] "openxlsx" "pak" +[29] "pdftools" "plotly" +[31] "promises" "pryr" +[33] "qpdf" "r-lib/ragg" +[35] "r-lib/rlang" "r-lib/systemfonts" +[37] "r-lib/textshaping" "r-lib/usethis" +[39] "r-rust/gifski" "ragg" +[41] "RcppRoll" "reshape2" +[43] "RinteRface/fullPage" "rintrojs" +[45] "rJava" "rlang" +[47] "rstudio/httpuv" "rsvg" +[49] "rtracklayer" "scales" +[51] "seqinr" "shiny" +[53] "shinyBS" "shinybusy" +[55] "shinycssloaders" "shinydashboard" +[57] "shinydisconnect" "shinyFeedback" +[59] "shinyjs" "shinythemes" +[61] "shinyvalidate" "shinyWidgets" +[63] "stringr" "svglite" +[65] "systemfonts" "tesseract" +[67] "textshaping" "tibble" +[69] "tictoc" "tidyverse" +[71] "usethis" "xfun" +[73] "xlsxjars" "zip" + +The following packages could not be installed: +[1] "pander" diff --git a/R/app.R b/R/app.R index f4c8197..72228bd 100644 --- a/R/app.R +++ b/R/app.R @@ -1,3 +1,6 @@ +Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library") +.libPaths(new = "/usr/local/lib/R/library") + source("R/global.R") ui <- fluidPage( diff --git a/R/global.R b/R/global.R index 97f5ce0..c071a88 100644 --- a/R/global.R +++ b/R/global.R @@ -1,52 +1,102 @@ +Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library") +.libPaths(new = "/usr/local/lib/R/library") + +options(shiny.maxRequestSize = 30000 * 1024^2) + suppressMessages({ - # Used packages - pacotes <- c( - "bslib", # customizing the appearance of Shiny applications using Bootstrap. - "data.table", # fast data manipulation and analysis. - "DT", # creating interactive and customizable data tables in R. - "dplyr", # data manipulation and transformation using a consistent grammar. - "fullPage", # creating full-page scrolling websites. - "future", - "ggasym", # creating asymmetric visualizations with ggplot2. - "ggpubr", # enhancing ggplot2 visualizations with publication-ready themes and annotations. - "glue", # interpolating strings and expressions in R. - "jsonify", - "kableExtra", # creating complex tables in R Markdown documents. - "openxlsx", # reading, writing, and manipulating Microsoft Excel files. - "promises", # creating and managing asynchronous programming in R. - "purrr", # functional programming and iterating over data structures. - "reshape2", # transforming and restructuring data in R. - "rintrojs", # creating interactive and guided tours in Shiny applications. - "rjson", # converts R object into JSON objects and vice-versa. - "rtracklayer", # read gff3 - "scales", # controlling the scaling of data in R graphics. - "seqinr", # extract fasta's name - "shiny", # building interactive web applications in R. - "shinyBS", # adding additional Bootstrap functionality to Shiny applications. - "shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools - "shinydashboard", # creating dashboards with a tabbed layout in Shiny. - "shinydisconnect", # handling disconnections and reconnections in Shiny applications. - "shinyFeedback", # providing user feedback and notifications in Shiny applications. - "shinycssloaders", # adding CSS loaders to Shiny applications. - "shinyjs", # easily incorporating JavaScript functions and events in Shiny applications. - "shinythemes", # customizing the appearance of Shiny applications with predefined themes. - "shinyvalidate", # client-side form validation in Shiny applications. - "shinyWidgets", # creating custom UI controls and widgets in Shiny. - "snow", # parallel computing using a simple network of workstations. - "tibble", # creating and manipulating data frames with enhanced features compared to traditional data frames. - "tidyverse", # data manipulation, visualization, and analysis. - "tictoc", # measuring the time taken by R code execution. - "shinyvalidate", # shinyvalidate adds input validation capabilities to Shiny. - "zip" # reading, writing, and manipulating ZIP archives in R. -) - - # verify required packages installed or not. If some package - # is missing, it will be installed automatically - package.check <- lapply(pacotes, FUN = function(x) { - if (!require(x, character.only = TRUE)) { - install.packages(x, dependencies = TRUE) - } - }) +# # Used packages +# pacotes <- c( +# "emayili", +# "bslib", # customizing the appearance of Shiny applications using Bootstrap. +# "data.table", # fast data manipulation and analysis. +# "DT", # creating interactive and customizable data tables in R. +# "dplyr", # data manipulation and transformation using a consistent grammar. +# "fullPage", # creating full-page scrolling websites. +# "future", +# "ggasym", # creating asymmetric visualizations with ggplot2. +# "ggpubr", # enhancing ggplot2 visualizations with publication-ready themes and annotations. +# "glue", # interpolating strings and expressions in R. +# "kableExtra", # creating complex tables in R Markdown documents. +# "openxlsx", # reading, writing, and manipulating Microsoft Excel files. +# "promises", # creating and managing asynchronous programming in R. +# "purrr", # functional programming and iterating over data structures. +# "reshape2", # transforming and restructuring data in R. +# "rintrojs", # creating interactive and guided tours in Shiny applications. +# "rjson", # converts R object into JSON objects and vice-versa. +# "rtracklayer", # read gff3 +# "scales", # controlling the scaling of data in R graphics. +# "seqinr", # extract fasta's name +# "shiny", # building interactive web applications in R. +# "shinyBS", # adding additional Bootstrap functionality to Shiny applications. +# "shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools +# "shinydisconnect", # handling disconnections and reconnections in Shiny applications. +# "shinyFeedback", # providing user feedback and notifications in Shiny applications. +# "shinycssloaders", # adding CSS loaders to Shiny applications. +# "shinyjs", # easily incorporating JavaScript functions and events in Shiny applications. +# "shinythemes", # customizing the appearance of Shiny applications with predefined themes. +# "shinyvalidate", # client-side form validation in Shiny applications. +# "shinyWidgets", # creating custom UI controls and widgets in Shiny. +# "snow", # parallel computing using a simple network of workstations. +# "tibble", # creating and manipulating data frames with enhanced features compared to traditional data frames. +# "tidyverse", # data manipulation, visualization, and analysis. +# "tictoc", # measuring the time taken by R code execution. +# "shinyvalidate", # shinyvalidate adds input validation capabilities to Shiny. +# "zip" # reading, writing, and manipulating ZIP archives in R. +# ) + +# # # verify required packages installed or not. If some package +# # # is missing, it will be installed automatically +# # package.check <- lapply(pacotes, FUN = function(x) { +# # if (!require(x, character.only = TRUE)) { +# # print(x) +# # install.packages(x, dependencies = TRUE) +# # } +# # }) + +# # 循环引入包 +# lapply(pacotes, function(pkg) { +# requireNamespace(pkg, quietly = TRUE) +# library(pkg, character.only = TRUE) +# }) + + # 显式地调用packages是因为renv的package管理需要识别library + library(jsonlite) + library(emayili) + library(bslib) + library(data.table) + library(DT) + library(dplyr) + library(fullPage) + library(future) + library(ggasym) + library(ggpubr) + library(glue) + library(kableExtra) + library(openxlsx) + library(promises) + library(purrr) + library(reshape2) + library(rintrojs) + library(rjson) + library(rtracklayer) + library(scales) + library(seqinr) + library(shiny) + library(shinyBS) + library(shinybusy) + library(shinydisconnect) + library(shinyFeedback) + library(shinycssloaders) + library(shinyjs) + library(shinythemes) + library(shinyvalidate) + library(shinyWidgets) + library(snow) + library(tibble) + library(tidyverse) + library(tictoc) + library(shinyvalidate) + library(zip) source("R/utils/utils.R") source("R/utils/shiny_busy_indicator.R") @@ -66,23 +116,21 @@ suppressMessages({ source("R/utils/motif_pair_gene_diagonal.R") }) -options(shiny.maxRequestSize = 30000 * 1024^2) -plan(multisession) - - -cpu_configuration <- readLines("data/cpu_configuration.txt") -NCPU <- cpu_configuration[1] +NCPU <- readLines("data/cpu_configuration.txt")[1] -# to detect the pre-computed motif-DB data -# when new daata comes, there is no need to change code. +# auto detect the pre-computed motif-DB data: when new species or motif database comes, no need to change code. species <- list.dirs("./data/indexing", recursive=F) %>% sapply(function(i) { str <- stringr::str_split_1(i, "/")[4] # %>% tolower() #%>% gsub("(^|\\s)([a-z])", "\\1\\U\\2", ., perl = TRUE) # capitablize first letter return(str) }) # > species -# ./data/indexing/arabidopsis_thaliana ./data/indexing/mais -# "arabidopsis_thaliana" "mais" +# ./data/indexing/Arabidopsis_thaliana +# "Arabidopsis_thaliana" +# ./data/indexing/Brachypodium_distachyon +# "Brachypodium_distachyon" +# ./data/indexing/Brassica_napus +# "Brassica_napus" MOTIF_DB <- lapply(species, function(speci) { @@ -93,10 +141,24 @@ MOTIF_DB <- lapply(species, function(speci) { for (i in seq(length(motif_dbs))) { result[[ list_names[i] ]] <- file.path("data/indexing", speci , motif_dbs[i]) } - return(result) }) %>% setNames(unname(species)) +# > MOTIF_DB +# $Arabidopsis_thaliana +# $Arabidopsis_thaliana$`CIS-BP2` +# [1] "data/indexing/Arabidopsis_thaliana/CIS-BP2" + +# $Arabidopsis_thaliana$`Franco-Zorrilla et al 2014` +# [1] "data/indexing/Arabidopsis_thaliana/Franco-Zorrilla_et_al_2014" + +# $Arabidopsis_thaliana$`Jaspar plants non redundant 2022` +# [1] "data/indexing/Arabidopsis_thaliana/Jaspar_plants_non_redundant_2022" +# $Arabidopsis_thaliana$`Plant Cistrome DB` +# [1] "data/indexing/Arabidopsis_thaliana/Plant_Cistrome_DB" + +# $Arabidopsis_thaliana$PlantTFDB +# [1] "data/indexing/Arabidopsis_thaliana/PlantTFDB" SPECIES_LIST <- list() @@ -105,5 +167,27 @@ for (speci in species) { SPECIES_LIST[[temp]] <- speci } SPECIES_LIST <- list(species = SPECIES_LIST) # to show nothing first of fileInput box +# > SPECIES_LIST +# $species +# $species$`Arabidopsis thaliana` +# [1] "Arabidopsis_thaliana" + +# $species$`Brachypodium distachyon` +# [1] "Brachypodium_distachyon" + +# $species$`Brassica napus` +# [1] "Brassica_napus" + +# $species$`Glycine max` +# [1] "Glycine_max" + +MOTF_DB_META <- rjson::fromJSON(file = "data/motif_db_meta.json") +# > MOTF_DB_META +# $Arabidopsis_thaliana +# $Arabidopsis_thaliana$genome_name +# [1] "Arabidopsis_thaliana.TAIR10.dna.toplevel.fa" + +# $Arabidopsis_thaliana$annotation_name +# [1] "Arabidopsis_thaliana.TAIR10.56.gff3" -MOTF_DB_META <- fromJSON(file = "data/motif_db_meta.json") \ No newline at end of file +# $Arabidopsis_thaliana$genome_link diff --git a/R/server/tab_visualize.R b/R/server/tab_visualize.R index 2f095ba..c1de763 100644 --- a/R/server/tab_visualize.R +++ b/R/server/tab_visualize.R @@ -381,3 +381,4 @@ observeEvent(pmet.result.processed(), { }) server_data("pmet_talble_tab", result) }) + diff --git a/R/ui/tab_test.R b/R/ui/tab_test.R index 6e2949a..5038ec1 100644 --- a/R/ui/tab_test.R +++ b/R/ui/tab_test.R @@ -1,3 +1,30 @@ +# tabPanel( +# title = "Test", +# value = "Test_tabpanel", +# tags$head( +# tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.css"), +# tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.js") +# ), +# tags$script(" +# $(document).ready(function() { +# new fullpage('#my-fullpage', { +# // fullPage.js options +# }); +# }); +# "), +# div(id = "my-fullpage", +# div(class = "section", +# actionButton("a", "a"), +# h1("Section 1") +# ), +# div(class = "section", +# h1("Section 2") +# ), +# div(class = "section", +# h1("Section 3") +# ) +# ) +# ) tabPanel( class = "tabPanel_shiny", "My Tab", diff --git a/R/utils/install_packages.R b/R/utils/install_packages.R index b356a88..64f229b 100755 --- a/R/utils/install_packages.R +++ b/R/utils/install_packages.R @@ -1,8 +1,11 @@ # 设置 CRAN 仓库 r <- getOption("repos") -r["CRAN"] <- "http://cran.us.r-project.org" +r["CRAN"] <- "https://cloud.r-project.org/" options(repos = r) -options(install.packages.compile.from.source = "always") +options(install.packages.compile.from.source = "auto") + +Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library") +.libPaths(new = "/usr/local/lib/R/library") ################################ install basic packages ################################# # 1. remotes and devtools @@ -10,12 +13,16 @@ options(install.packages.compile.from.source = "always") # 3. pak # 定义一个辅助函数来安装包并在失败时终止程序 install_and_check_func <- function(package) { - if (!requireNamespace(package, quietly = TRUE)) { - suppressMessages(install.packages(package, quiet = TRUE)) + result <- suppressWarnings(suppressMessages(capture.output({ if (!requireNamespace(package, quietly = TRUE)) { - stop(paste("Failed to install", package, ". Terminating the program.")) + install.packages(package, quiet = TRUE) + if (!requireNamespace(package, quietly = TRUE)) { + return(FALSE) # 如果再次检查仍然未安装,返回 FALSE + } } - } + return(TRUE) # 如果已安装或安装成功,返回 TRUE + }))) + return(result) } # 安装 devtools remotes 和 BiocManager 包 @@ -24,65 +31,61 @@ install_and_check_func("remotes") install_and_check_func("BiocManager") # 尝试安装 pak 包 -if (!requireNamespace("pak", quietly = TRUE)) { - suppressMessages(install.packages("pak", quiet = TRUE)) +suppressWarnings(suppressMessages(capture.output( if (!requireNamespace("pak", quietly = TRUE)) { - suppressMessages(remotes::install_github("r-lib/pak")) + install.packages("pak", quiet = TRUE) if (!requireNamespace("pak", quietly = TRUE)) { - stop("Failed to install pak from both CRAN and GitHub. Terminating the program.") + remotes::install_github("r-lib/pak", quiet = TRUE) + if (!requireNamespace("pak", quietly = TRUE)) { + stop("Failed to install pak from both CRAN and GitHub. Terminating the program.") + } } } -} +))) ################################ install function ################################# install_package_func <- function(package_name) { - # 提取包名:如果包名包含 '/', 提取斜线后的部分 package_name_to_check <- ifelse(grepl("/", package_name), sub(".*/", "", package_name), package_name) - - # 检查包是否已经安装 if (requireNamespace(package_name_to_check, quietly = TRUE)) { return(TRUE) } - # 定义一个列表,包含尝试安装包的不同函数 install_functions <- list( - bio_install = function() suppressMessages(BiocManager::install(package_name, ask = FALSE)), - devtools_install = function() suppressMessages(devtools::install_github(package_name, quiet = TRUE)), - remotes_install = function() suppressMessages(remotes::install_github(package_name, quiet = TRUE)), - normal_install = function() suppressMessages(install.packages(package_name, repos = "https://cran.r-project.org", dependencies = TRUE, type = "source", quiet = TRUE)), - pak_install = function() suppressMessages(pak::pak(package_name)) + bio_install = function() BiocManager::install(package_name, ask = FALSE, quietly = TRUE), + devtools_install = function() devtools::install_github(package_name, quiet = TRUE), + remotes_install = function() remotes::install_github(package_name, quiet = TRUE), + normal_install = function() install.packages(package_name, repos = "https://cran.r-project.org", dependencies = TRUE, type = "source", quiet = TRUE), + pak_install = function() pak::pak(package_name, ask = FALSE) ) - # 遍历安装函数,尝试安装包 for (install_func in install_functions) { - tryCatch({ - install_func() - - # 检查是否安装成功 - if (requireNamespace(package_name, quietly = TRUE)) { - return(TRUE) # 成功安装,返回 TRUE - } - }, error = function(e) {}) + suppressWarnings(suppressMessages(capture.output( + tryCatch({ + install_func() + if (requireNamespace(package_name, quietly = TRUE)) { + return(TRUE) + } + }, error = function(e) {}) + ))) } - # 所有方法尝试完毕,安装失败 return(FALSE) } ################################ installation ################################ # bio -packages_bio <- c("rtracklayer", "DESeq2", "WGCNA", "GEOqueary", "limma", "edgeR", - "GSEABase", "clusterProfiler", "ConsensusClusterPlus", "GSVA", - "pheatmap", "scFeatureFilter", "AUCell", "ComplexHeatmap") +# packages_bio <- c("rtracklayer", "DESeq2", "WGCNA", "GEOqueary", "limma", "edgeR", +# "GSEABase", "clusterProfiler", "ConsensusClusterPlus", "GSVA", +# "pheatmap", "scFeatureFilter", "AUCell", "ComplexHeatmap") +packages_bio <- c("rtracklayer") # normal packages packages_normal <- c( - "future", - "qs", + "jsonlite", + "jsonify", "ddpcr", "rlang", "pander", "pacman", - "pagoda2", "eulerr", "Hmisc", "pryr", @@ -91,7 +94,6 @@ packages_normal <- c( "RcppRoll", "msigdbr", "xlsxjars", - "shiny", "svglite", "pak", "devtools", @@ -108,7 +110,7 @@ packages_normal <- c( "stringr", "usethis", "httpuv", - "Seurat", + "rJava", "bslib", # Bootstrap themes and styles "data.table", # efficient handling of large datasets "DT", # interactive data tables @@ -119,25 +121,22 @@ packages_normal <- c( "ggplot2", # creation of beautiful graphics "ggpubr", # graph publication-ready formatting and annotations "glue", # string interpolation and formatting - "jsonify", # JSON data processing and transformation "kableExtra", # creation of nice tables and adding formatting - "mailR", # Interface to Apache Commons Email to send emails from R "openxlsx", # reading and writing Excel files "promises", # deferred evaluation and asynchronous programming "reshape2", # data reshaping and transformation "rintrojs", # interactive tour integration - "rjson", # Converts R object into JSON objects and vice-versa "shiny", # creation of interactive web applications - "rJava", "shinyBS", # Bootstrap styling "shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools - "shinydashboard", # creation of dashboard-style Shiny apps "shinyFeedback", # user feedback integration "shinycssloaders", # loading animation integration "shinyjs", # JavaScript operations "shinythemes", # theme customization "shinyvalidate", # form validation "shinyWidgets", # creation of interactive widgets + "shinydisconnect", + "shinydashboard", "scales", # data scaling and transformation "seqinr", # extract fasta's name "tibble", # extended data frames @@ -150,28 +149,21 @@ packages_normal <- c( pak_packages <- c("r-lib/ragg", "r-lib/usethis", "r-lib/rlang") # github packages_github <- c( - "daattali/shinydisconnect", - "RinteRface/fullPage", - "dreamRs/shinybusy", - "merlinoa/shinyFeedback", - "daattali/shinycssloaders", - "dreamRs/shinyWidgets", - "r-lib/textshaping", - "r-lib/systemfonts", - "jhrcook/ggasym", - "rpremrajGit/mailR", - "r-lib/textshaping", - "rstudio/httpuv", - "r-rust/gifski", - "jhrcook/ggasym", - "satijalab/seurat-data", - "satijalab/azimuth", - "satijalab/seurat-wrappers", - "stuart-lab/signac", - "satijalab/seurat", - "jhrcook/ggasym", - "kharchenkolab/pagoda2", - "NMikolajewicz/scMiko") + "jeroen/jsonlite", + "kassambara/ggpubr", + "SymbolixAU/jsonify", + "daattali/shinydisconnect", + "datawookie/emayili", + "RinteRface/fullPage", + "dreamRs/shinybusy", + "merlinoa/shinyFeedback", + "daattali/shinycssloaders", + "dreamRs/shinyWidgets", + "r-lib/textshaping", + "r-lib/systemfonts", + "rstudio/httpuv", + "r-rust/gifski", + "jhrcook/ggasym") installed_packages <- character(0) failed_packages <- character(0) @@ -207,12 +199,12 @@ for (package in packages) { ############################## summary ############################ # Print installed packages cat("The installed packages are as follows:\n") -print(sort(installed_packages)) +print(sort(unique(installed_packages))) # Print failed packages if (length(failed_packages) > 0) { cat("\nThe following packages could not be installed:\n") - print(failed_packages) + print(unique(failed_packages)) } else { cat("\nAll packages were successfully installed.\n") } \ No newline at end of file diff --git a/R/utils/send_mail.R b/R/utils/send_mail.R index 8d1ae9f..4f067df 100644 --- a/R/utils/send_mail.R +++ b/R/utils/send_mail.R @@ -38,7 +38,6 @@ # result_link <- args[2] # SendResultMail(recipient = recipient, result_link = result_link) -library(emayili) SendResultMail <- function(recipient = NULL, result_link = NULL) { diff --git a/app.R b/app.R index 794b40a..6ebdb0a 100644 --- a/app.R +++ b/app.R @@ -1,3 +1,6 @@ +Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library") +.libPaths(new = "/usr/local/lib/R/library") + source("R/app.R") shinyApp(ui = ui, server = server) diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..dbf6cfa --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,12 @@ +server { + listen 84; + listen [::]:84; + server_name localhost_pmet; + + # access_log /var/log/nginx/localhost.access.log; + + location /result { + # autoindex on; + alias /usr/share/nginx/pmet; + } +} diff --git a/conf/shiny-server.conf b/conf/shiny-server.conf new file mode 100644 index 0000000..68d48a1 --- /dev/null +++ b/conf/shiny-server.conf @@ -0,0 +1,21 @@ +# Instruct Shiny Server to run applications as the user "shiny" +run_as shiny; + +# Define a server that listens on port 3838 +server { + listen 3838; + + # Define a location at the base URL + location / { + app_idle_timeout 0; + # Host the directory of Shiny Apps stored in this directory + site_dir /srv/shiny-server; + + # Log all Shiny output to files in this directory + log_dir /var/log/shiny-server; + + # When a user visits the base URL rather than a particular application, + # an index of the applications available in this directory will be shown. + directory_index on; + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b8ab219 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +x-yml-version: '3.8' + +services: + shiny-app: + build: + context: . + dockerfile: dockerfiles/Dockerfile.shiny + volumes: + - ./result:/home/shiny/PMET_docker/result + - ./logs:/var/log/shiny-server + ports: + - "3838:3838" + networks: + - app-network + + nginx-server: + build: + context: . + dockerfile: dockerfiles/Dockerfile.nginx + container_name: test_nginx + volumes: + - ./result:/usr/share/nginx/pmet + ports: + - "84:84" + restart: always + networks: + - app-network + + +volumes: + logs: + result: + +networks: + app-network: diff --git a/dockerfiles/Dockerfile.nginx b/dockerfiles/Dockerfile.nginx new file mode 100644 index 0000000..0af436e --- /dev/null +++ b/dockerfiles/Dockerfile.nginx @@ -0,0 +1,14 @@ +# Use the official Nginx image as the base image +FROM nginx:latest + +# 创建结果目录 +RUN mkdir -p /usr/share/nginx/pmet && \ + chmod -R 777 /usr/share/nginx/pmet + +COPY ./conf/nginx.conf /etc/nginx/conf.d/pmet.conf + +# Expose Nginx's default port +EXPOSE 84 + +# Start Nginx service +CMD ["nginx", "-g", "daemon off;"] diff --git a/dockerfiles/Dockerfile.shiny b/dockerfiles/Dockerfile.shiny new file mode 100644 index 0000000..c973767 --- /dev/null +++ b/dockerfiles/Dockerfile.shiny @@ -0,0 +1,109 @@ +FROM rocker/shiny:4.3.3 + +############################## 1. shiny setting ############################### +COPY ./conf/shiny-server.conf /etc/shiny-server/shiny-server.conf + +ENV work_dir="/home/shiny/PMET_docker" +COPY . $work_dir + +RUN ln -sf $work_dir /srv/shiny-server/pmet + +# Use the find command to find all .sh, .r, .py, .pl files and grant them 755 permissions +RUN find $work_dir/ \( -name "*.sh" -o -name "*.r" -o -name "*.py" -o -name "*.pl" \) -exec chmod 777 {} \; + + +############################## 2. install linux libs ############################### +RUN $work_dir/scripts/install_apt_tools.sh + + +# ############################## 3. R libs settings ############################### +ENV R_LIBS_USER=/usr/local/lib/R/library +# Set the directory owner and permissions +RUN mkdir -p $R_LIBS_USER && \ + chmod -R 777 $R_LIBS_USER +# Set environment variables in respective user profiles +RUN echo "export R_LIBS_USER='$R_LIBS_USER'" >> /root/.bashrc && \ + echo "export R_LIBS_USER='$R_LIBS_USER'" >> /home/shiny/.bashrc && \ + echo "R_LIBS_USER='$R_LIBS_USER'" >> /root/.Renviron && \ + echo "R_LIBS_USER='$R_LIBS_USER'" >> /home/shiny/.Renviron + + +############################## 4. install R libs ############################### +# # Configure Java using R CMD javareconf +RUN sudo R CMD javareconf + +# # renv for package management +# RUN Rscript -e "install.packages(c('remotes', 'littler', 'docopt', 'renv', 'jsonlite'))" +# RUN Rscript -e "renv::restore()" +RUN Rscript $work_dir/R/utils/install_packages.R + +RUN rsync -av --ignore-existing /usr/local/lib/R/library/ /usr/local/lib/R/site-library/ && \ + rsync -av --ignore-existing /usr/local/lib/R/site-library/ /usr/local/lib/R/library/ + + +############################## 5. install python libs ############################### +RUN sudo apt-get update && \ + apt -y install python3-pip +RUN $work_dir/scripts/install_python_libs.sh + + +########################## 6. install bedtool and samtools ########################### +RUN apt -y install bedtools + +# Samtools 1.3.1 # +ENV SAMTOOLS_INSTALL_DIR=/opt/samtools +ENV HTSLIB_INSTALL_DIR=/opt/htslib + +WORKDIR /tmp +RUN wget https://github.com/samtools/samtools/releases/download/1.17/samtools-1.17.tar.bz2 && \ + tar -xjf samtools-1.17.tar.bz2 && \ + cd samtools-1.17 && \ + ./configure --disable-lzma --prefix=$SAMTOOLS_INSTALL_DIR && \ + make && \ + make install && \ + cd / && \ + rm -rf /tmp/samtools-1.17 /tmp/samtools-1.17.tar.bz2 +# Set the working directory back to the root directory +WORKDIR $work_dir + + +################################## 7. compile pmet ################################### +# meme +RUN cd $work_dir/PMETdev/src/meme-5.5.3 \ + && aclocal \ + && automake \ + && mkdir -p build \ + && chmod a+x ./configure \ + && ./configure --prefix=$work_dir/PMETdev/src/meme-5.5.3/build --enable-build-libxml2 --enable-build-libxslt \ + && make \ + && make install \ + && chmod a+x build/bin/fimo \ + && cp build/bin/fimo $work_dir/PMETdev/scripts/ \ + && make distclean \ + && rm -rf build + +# pmetindex +RUN cd $work_dir/PMETdev/src/indexing \ + && chmod a+x build.sh \ + && bash build.sh \ + && mv bin/pmetindex $work_dir/PMETdev/scripts/ + +# pmetParallel +RUN cd $work_dir/PMETdev/src/pmetParallel \ + && chmod a+x build.sh \ + && bash build.sh \ + && mv bin/pmetParallel_linux $work_dir/PMETdev/scripts/ + +# pmet +RUN cd $work_dir/PMETdev/src/pmet \ + && chmod a+x build.sh \ + && bash build.sh \ + && mv bin/pmet $work_dir/PMETdev/scripts/ + + +############################# 8. download homotypic data ############################## +RUN $work_dir/scripts/download_pmet_indexing.sh + + +EXPOSE 3838 +CMD ["/usr/bin/shiny-server"] diff --git a/readme.md b/readme.md index acbedb4..f0e52af 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,11 @@ This is a Shiny app developed for PMET. ```shell . +├── conf * # configure for shiny server and nginx +├── data +├── dockerfiles ├── PMETdev +├── indexing ├── R │ ├── app.R │ ├── global.R @@ -16,22 +20,30 @@ This is a Shiny app developed for PMET. │ ├── server │ ├── ui │ └── utils -├── data -│ ├── indexing -├── deploy_one_bash.sh * # ONLY to run this bash to deploy ├── result ├── www +├── 01_deploy_via_bash.sh +├── 01_deploy_via_Docker.sh * # Recommended installation method +├── app.R * # Shiny app +├── docker-compose.yml ├── PMET-Shiny-App.Rproj -├── app.R └── readme.md ``` ## 2. Quick deployment +### 2.1 (option one) Install on Docker (Recommended) + +```bash +bash 01_deploy_via_Docker.sh +``` + +### 2.2 (option two) Bash install on current Debian-like OS 1. Install `Shiny Server` and `Nginx` [[details](#setup-shiny-server-and-nginx)] -2. `git clone` or `git pull` in the folder of Shiny Server (default: `/srv/shiny-server`)![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202309191728114.png) +2. `git clone` in the folder of Shiny Server (default: `/srv/shiny-server`) or git clone anywhere and then create a link under `/srv/shiny-server` as shown below: +![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202309191728114.png) -3. Run `deploy_one_bash.sh` +1. Run `01_deploy_via_bash.sh` - 1. set email and CPU - 2. assign execute permissions @@ -41,10 +53,20 @@ This is a Shiny app developed for PMET. - 6. install python packages - 7. Install tools (`GNU Parallel`, `bedtools`, `samtools`, `MEME`...)[[details](#tools)] ```bash - bash deploy_one_bash.sh + bash 01_deploy_via_bash.sh ``` ![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202310190148145.png) + + + +--- + +**If not necessary, there is no need to read the following content.** + +--- + + ## 3. Pre-computed homotypic motif hits of plant species (PMET indexing data) Given that the PMET indexing calculation takes a very long time, we have already performed pre-calculation for some plants and several common plant transcription factor databases. @@ -54,9 +76,6 @@ The data can be accessed by running the script `deploy_one_bash.sh` from [Homoty ```bash bash deploy_one_bash.sh -# ... -# 3. Would you like to download data of homotypic motif hits? [y/N]: Y -``` ```shell # file tree @@ -108,7 +127,7 @@ bash binary_compile.sh After compilation, the executable will be saved in the `PMETdev/scripts` directory for the Shiny app to call. -## Setup 5. Shiny server and nginx +## 5. Shiny server and nginx **5.1 Shiny-server and nginx install** @@ -143,94 +162,8 @@ server { } ``` - - -## 6. Tools needed - -**6.1 Install GNU Parallel** - -GNU Parallel helps PMET index (FIMO and PMET index) to run in parallel mode. - -```bash -sudo apt-get install parallel - -# Put GNU Parallel silent -parallel --citation -``` - -**6.2 Install The MEME Suite (FIMO and fasta-get-markov)** - -```bash -# cd a folder you want to put the software -mkdir -p ./tools - -cd ./tools -wget https://meme-suite.org/meme/meme-software/5.5.2/meme-5.5.2.tar.gz -tar zxf meme-5.5.2.tar.gz - -cd meme-5.5.2 -./configure --prefix=$(pwd) --enable-build-libxml2 --enable-build-libxslt -make -make install - -echo "export PATH=$(pwd)/bin:\$PATH" >> ~/.bashrc -source ~/.bashrc -cd .. -rm meme-5.5.2.tar.gz -``` - - -**6.3 Install samtools** -Install from conda or mamba: - -```bash -conda install -c bioconda samtools -``` - -Install from source: - -```bash -mkdir -p ./tools - -cd ./tools -wget https://github.com/samtools/samtools/releases/download/1.17/samtools-1.17.tar.bz2 -tar -xjf samtools-1.17.tar.bz2 - -cd samtools-1.17 -./configure --prefix=$(pwd) -make -make install -# Add following into bash profile file or .zshrc (if zsh used). -echo "export PATH=$(pwd)/bin:\$PATH" >> ~/.bashrc -source ~/.bashrc - -cd .. -rm samtools-1.17.tar.bz2 -``` - -**6. 4 Install bedtools** -```bash -# Debian/Ubuntu -apt-get install bedtools -# Fedora/Centos -yum install BEDTools -``` - -or - -```bash -wget https://github.com/arq5x/bedtools2/releases/download/v2.29.1/bedtools-2.29.1.tar.gz -tar -zxvf bedtools-2.29.1.tar.gz -cd bedtools2 -make -``` +## PMET workflow ![](www/figures/pmet_workflow_with_interval_option.png) [GitHub Ribbons](https://github.blog/2008-12-19-github-ribbons/) diff --git a/scripts/bin/install2.r b/scripts/bin/install2.r new file mode 100644 index 0000000..33cab2c --- /dev/null +++ b/scripts/bin/install2.r @@ -0,0 +1,168 @@ +#!/usr/bin/env r +# +# A second example to install one or more packages, now with option parsing +# +# Copyright (C) 2011 - 2014 Dirk Eddelbuettel +# Copyright (C) 2014 - 2017 Carl Boettiger and Dirk Eddelbuettel +# Copyright (C) 2018 - 2023 Carl Boettiger, Dirk Eddelbuettel, Brandon Bertelsen, and SHIMA Tatsuya +# +# Released under GPL (>= 2) + +## load docopt package from CRAN +library(docopt) + +## default to first library location in .libPaths() +libloc <- .libPaths()[1] + +## configuration for docopt +doc <- paste0("Usage: install2.r [-l LIBLOC] [-h] [-x] [-s] [-d DEPS] [-n NCPUS] [-r REPOS...] [-m METHOD] [-t TYPE] [--error] [--skipmissing] [--] [PACKAGES ...] + +-l --libloc LIBLOC location in which to install [default: ", libloc, "] +-d --deps DEPS install suggested dependencies as well [default: NA] +-n --ncpus NCPUS number of processes to use for parallel install, -1 selects all cores [default: getOption] +-r --repos REPOS repositor(y|ies) to use, or NULL for file [default: getOption] +-e --error throw error and halt instead of a warning [default: FALSE] +--skipmissing use with the --error option, skip the packages missing error [default: FALSE] +-s --skipinstalled skip installing already installed packages [default: FALSE] +-m --method METHOD method to be used for downloading files [default: auto] +-t --type TYPE installation type as used by `install.packages` [default: getOption] +-h --help show this help text +-x --usage show help and short example usage") +opt <- docopt(doc) # docopt parsing + +if (opt$usage) { + cat(doc, "\n\n") + cat("where PACKAGES... can be one or more CRAN package names, or local (binary or source) +package files (where extensions .tar.gz, .tgz and .zip are recognised). Optional +arguments understood by R CMD INSTALL can be passed interspersed in the PACKAGES, though +this requires use of '--'. + +Examples: + install2.r -l /tmp/lib Rcpp BH # install into given library + install2.r -- --with-keep.source drat # keep the source + install2.r -- --data-compress=bzip2 stringdist # prefer bz2 compression + install2.r \".\" # install package in current directory + install2.r -n 6 ggplot2 # parallel install: (6 processes) + +install2.r is part of littler which brings 'r' to the command-line. +See https://dirk.eddelbuettel.com/code/littler.html for more information.\n") + q("no") +} + +if (opt$deps == "TRUE" || opt$deps == "FALSE") { + opt$deps <- as.logical(opt$deps) +} else if (opt$deps == "NA") { + opt$deps <- NA +} + +## docopt results are characters, so if we meant NULL we have to set NULL +if (length(opt$repos) == 1 && "NULL" %in% opt$repos) { + opt$repos <- NULL +} + +if ("getOption" %in% opt$repos) { + ## as littler can now read ~/.littler.r and/or /etc/littler.r we can preset elsewhere + opt$repos <- c(opt$repos[which(opt$repos != "getOption")], getOption("repos")) +} + +if (opt$ncpus == "getOption") { + opt$ncpus <- getOption("Ncpus", 1L) +} else if (opt$ncpus == "-1") { + ## parallel comes with R 2.14+ + opt$ncpus <- max(1L, parallel::detectCores()) +} + +## type should reflects bspm where available +if (opt$type == "getOption") { + opt$type <- getOption("pkgType") + #if (requireNamespace("bspm", quietly=TRUE) && Sys.info()[["sysname"]] == "Linux") opt$type <- "binary-source" + +} + +## ensure installation is stripped +Sys.setenv("_R_SHLIB_STRIP_"="true") + +install_packages2 <- function(pkgs, ..., error = FALSE, skipmissing = FALSE, skipinstalled = FALSE) { + e <- NULL + capture <- function(e) { + if (error) { + catch <- + grepl("(download|installation) of package .* failed", e$message) || + (grepl("(dependenc|package).*(is|are) not available", e$message) && !skipmissing) || + grepl("installation of package.*had non-zero exit status", e$message) || + grepl("installation of .+ package(|s) failed", e$message) + if (catch) { + e <<- e + } + } + } + if (skipinstalled) { + pkgs <- setdiff(pkgs, installed.packages()[,1]) + } + if (length(pkgs) > 0) { + withCallingHandlers(install.packages(pkgs, ...), warning = capture) + if (!is.null(e)) { + stop(e$message, call. = FALSE) + } + } +} + +## helper function to for existing files with matching extension +isMatchingFile <- function(f) (file.exists(f) && grepl("(\\.tar\\.gz|\\.tgz|\\.zip)$", f)) || (f == ".") + +## helper function which switches to local (ie NULL) repo if matching file is presented +installArg <- function(f, lib, rep, dep, iopts, error, skipmissing, skipinstalled, ncpus, method, type) { + install_packages2(pkgs=f, + lib=lib, + repos=if (isMatchingFile(f)) NULL else rep, + dependencies=dep, + INSTALL_opts=iopts, + Ncpus = ncpus, + method = method, + type = type, + error = error, + skipmissing = skipmissing, + skipinstalled = skipinstalled) +} + +## strip out arguments to be passed to R CMD INSTALL +isArg <- grepl('^--',opt$PACKAGES) +installOpts <- opt$PACKAGES[isArg] +opt$PACKAGES <- opt$PACKAGES[!isArg] + +if (length(opt$PACKAGES)==0 && file.exists("DESCRIPTION") && file.exists("NAMESPACE")) { + ## we are in a source directory, so build it + message("* installing *source* package found in current working directory ...") + opt$PACKAGES <- "." +} + +## helper function to for existing files with matching extension +isMatchingFile <- + function(f) (file.exists(f) && + grepl("(\\.tar\\.gz|\\.tgz|\\.zip)$", f)) || (f == ".") + +## check arguments for local files -- if none, then we can pass vector on +isLocal <- sapply(opt$PACKAGES, isMatchingFile) + +## for any local sources loop explicitly as before, otherwise for remote +## packages pass vector to install_packages2 which does the rest (and +## possibly in parallel using up to ncpus) +if (any(isLocal)) { + sapply(opt$PACKAGES, installArg, opt$libloc, opt$repos, opt$deps, + installOpts, opt$error, opt$skipmissing, opt$skipinstalled, opt$ncpus, opt$method, opt$type) +} else { + install_packages2(pkgs = opt$PACKAGES, + lib = opt$libloc, + repos = opt$repos, + dependencies = opt$deps, + INSTALL_opts = installOpts, + Ncpus = opt$ncpus, + method = opt$method, + type = opt$type, + error = opt$error, + skipmissing = opt$skipmissing, + skipinstalled = opt$skipinstalled) +} + +## clean up any temp file containing CRAN directory information +sapply(list.files(path=tempdir(), pattern="^(repos|libloc).*\\.rds$", full.names=TRUE), unlink) diff --git a/scripts/check_CPU_number.sh b/scripts/check_CPU_number.sh new file mode 100644 index 0000000..b906902 --- /dev/null +++ b/scripts/check_CPU_number.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +source scripts/colored_print.sh + +# Function to get user input for CPU number +get_cpu_number() { + while true; do + print_fluorescent_yellow_no_br " Please enter a number for CPU configuration: " + read cpu_number + if [[ "$cpu_number" =~ ^[0-9]+$ ]]; then + echo "$cpu_number" > "$file_path" + echo " CPU number: $cpu_number" + break + else + print_red " Invalid input. Please enter a numeric value." + fi + done +} + +# 函数:检查CPU配置文件是否存在,并提示用户 +check_cpu_number() { + file_path="data/cpu_configuration.txt" + + # 检查文件是否存在且不为空 + if [ ! -f "$file_path" ] || [ ! -s "$file_path" ]; then + get_cpu_number + else + cpu_number=$(cat "$file_path") + # print_orange " Check your CPU number in $file_path" + echo " Number of CPU: $cpu_number" + + # 询问用户是否要修改CPU数量 + while true; do + print_orange_no_br " Do you want to modify the CPU number? [y/N]: " + read modify + + modify=${modify:-N} # 默认为'N',如果没有提供输入 + case "$modify" in + [Yy]* ) + get_cpu_number + break + ;; + [Nn]* ) + # echo "Keeping the existing CPU configuration: $cpu_number" + break + ;; + * ) + print_red "Please answer yes (y) or no (n)." + ;; + esac + done + fi +} + +# 导出函数,以便在source a.sh后可以被调用 +export -f get_cpu_number +export -f check_cpu_number diff --git a/scripts/check_and_set_email_credentials.sh b/scripts/check_and_set_email_credentials.sh new file mode 100644 index 0000000..a94ec54 --- /dev/null +++ b/scripts/check_and_set_email_credentials.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +source scripts/colored_print.sh + +# 定义函数 check_and_set_email_credentials +check_and_set_email_credentials() { + + credential_path="data/email_credential.txt" + + # 初始化 file_flag 为 F,表示默认情况下文件状态为不满足条件 + file_flag="F" + # 检查文件是否存在,且至少有5行非空内容 + if [[ -f "$credential_path" ]] && [[ $(grep -v '^[[:blank:]]*$' "$credential_path" | wc -l) -ge 5 ]]; then + print_orange " Please check your email credential in $credential_path" + # 读取文件内容到变量 + readarray -t lines < "$credential_path" + username="${lines[0]}" + password="${lines[1]}" + address="${lines[2]}" + smtp_link="${lines[3]}" + ssl_port="${lines[4]}" + echo " User name (email): $username" + echo " Password : $password" + echo " Address : $address" + echo " SMTP Link : $smtp_link" + echo " SSL Port : $ssl_port" + + print_orange_no_br " Is this information correct? (Y/n): " + read confirmation + confirmation=${confirmation:-Y} # 如果用户没有输入任何内容,则将 confirmation 设置为 'Y' + if [[ "$confirmation" =~ ^[Yy]$ ]]; then + file_flag="T" + else + file_flag="F" + fi + else + current_date=$(date '+%Y%m%d%H%M') + + # 检查文件是否存在 + if [[ -f "$credential_path" ]]; then + # 构造新的文件名 + new_filename="data/email_credential_${current_date}.txt" + + mv "$credential_path" "$new_filename" + print_red " Invalid email credential: $credential_path" + print_red " The file has been renamed to '$new_filename'." + else + print_red " Email credential '$credential_path' does not exist." + fi + + file_flag="F" + fi + + # 根据 file_flag 做进一步操作 + if [[ "$file_flag" == "F" ]]; then + print_orange " Please provide the required information." + rm -rf "$credential_path" + touch "$credential_path" + # 循环直到输入非空的用户名 + while true; do + read -p " User name (email): " username + # 检查用户名是否非空 + if [[ -z "$username" ]]; then + print_red " Email (User name) cannot be empty. Please try again." + else + break # 用户名非空,跳出循环 + fi + done + # 循环直到输入非空的密码 + while true; do + read -p " Password : " password + if [[ -z "$password" ]]; then + print_red " Password cannot be empty. Please try again." + else + break # 密码非空,跳出循环 + fi + done + # 循环直到输入非空的address + while true; do + read -p " Address (email): " address + # 检查用户名是否非空 + if [[ -z "$address" ]]; then + print_red " Address (email) cannot be empty. Please try again." + else + break # 用户名非空,跳出循环 + fi + done + # 接收并验证 SMTP 链接 + while true; do + read -p " SMTP link: " smtp_link + if [[ -n "$smtp_link" ]]; then + break + else + print_red " SMTP link cannot be empty. Please try again." + fi + done + # 接收并验证 SSL 端口号 + while true; do + read -p " SSL Port : " ssl_port + if [[ -n "$ssl_port" ]] && [[ "$ssl_port" -ne 0 ]]; then + break + else + print_red " SSL Port cannot be zero or empty. Please try again." + fi + done + echo + + # 存储信息到文件 Store information to file + echo "$username" >> "$credential_path" + echo "$password" >> "$credential_path" + echo "$address" >> "$credential_path" + echo "$smtp_link" >> "$credential_path" + echo "$ssl_port" >> "$credential_path" + # show message + { + read -r username + read -r password + read -r address + read -r smtp_link + read -r ssl_port + } < "$credential_path" + print_green " User name: $username" + print_green " Password : $password" + print_green " Address : $address" + print_green " User name: $smtp_link" + print_green " Password : $ssl_port" + fi +} + +# 导出函数,使其在source a.sh后可以被调用 +export -f check_and_set_email_credentials diff --git a/scripts/cleanup_Docker.sh b/scripts/cleanup_Docker.sh new file mode 100644 index 0000000..23ef95e --- /dev/null +++ b/scripts/cleanup_Docker.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# 停止所有运行中的容器 +echo "Stopping all running containers..." +docker stop $(docker ps -q) + +# 删除所有容器 +echo "Removing all containers..." +docker rm $(docker ps -aq) + +# 删除所有镜像 +echo "Removing all images..." +docker rmi $(docker images -q) + +# 可选:删除所有悬空镜像(dangling images) +echo "Removing all dangling images..." +docker image prune -af + +# 可选:删除所有未使用的容器、镜像、卷和网络 +echo "Pruning all unused containers, images, volumes, and networks..." +docker system prune --volumes + +# 可选:清理构建缓存 +echo "Pruning build cache..." +docker builder prune --all + +echo "Cleanup is complete." diff --git a/scripts/colored_print.sh b/scripts/colored_print.sh new file mode 100644 index 0000000..e9caeca --- /dev/null +++ b/scripts/colored_print.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +if [ true ]; then + print_red(){ + RED='\033[0;31m' + NC='\033[0m' # No Color + printf "${RED}$1${NC}\n" + } + print_green(){ + GREEN='\033[0;32m' + NC='\033[0m' # No Color + printf "${GREEN}$1${NC}\n" + } + print_green_no_br(){ + GREEN='\033[0;32m' + NC='\033[0m' # No Color + printf "${GREEN}$1${NC}" + } + print_orange(){ + ORANGE='\033[0;33m' + NC='\033[0m' # No Color + printf "${ORANGE}$1${NC}\n" + } + print_orange_no_br(){ + ORANGE='\033[0;33m' + NC='\033[0m' # No Color + printf "${ORANGE}$1${NC}" + } + print_fluorescent_yellow(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + printf "${FLUORESCENT_YELLOW}$1${NC}\n" + } + print_fluorescent_yellow_no_br(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + printf "${FLUORESCENT_YELLOW}$1${NC}" + } + print_white(){ + WHITE='\033[1;37m' + NC='\033[0m' # No Color + printf "${WHITE}$1${NC}" + } + print_middle(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + # 获取终端的宽度 + COLUMNS=$(tput cols) + # 遍历每一行 + while IFS= read -r line; do + # 计算需要的空格数来居中文本 + padding=$(( (COLUMNS - ${#line}) / 2 )) + printf "%${padding}s" '' + printf "${FLUORESCENT_YELLOW}${line}${NC}\n" + done <<< "$1" + } +fi diff --git a/scripts/download_pmet_indexing.sh b/scripts/download_pmet_indexing.sh new file mode 100644 index 0000000..fc19d53 --- /dev/null +++ b/scripts/download_pmet_indexing.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +if [ true ]; then + print_red(){ + RED='\033[0;31m' + NC='\033[0m' # No Color + printf "${RED}$1${NC}\n" + } + + print_green(){ + GREEN='\033[0;32m' + NC='\033[0m' # No Color + printf "${GREEN}$1${NC}\n" + } + + print_green_no_br(){ + GREEN='\033[0;32m' + NC='\033[0m' # No Color + printf "${GREEN}$1${NC}" + } + + print_orange(){ + ORANGE='\033[0;33m' + NC='\033[0m' # No Color + printf "${ORANGE}$1${NC}\n" + } + print_orange_no_br(){ + ORANGE='\033[0;33m' + NC='\033[0m' # No Color + printf "${ORANGE}$1${NC}" + } + + print_fluorescent_yellow(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + printf "${FLUORESCENT_YELLOW}$1${NC}\n" + } + print_fluorescent_yellow_no_br(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + printf "${FLUORESCENT_YELLOW}$1${NC}" + } + + print_white(){ + WHITE='\033[1;37m' + NC='\033[0m' # No Color + printf "${WHITE}$1${NC}" + } + + print_middle(){ + FLUORESCENT_YELLOW='\033[1;33m' + NC='\033[0m' # No Color + # 获取终端的宽度 + COLUMNS=$(tput cols) + # 遍历每一行 + while IFS= read -r line; do + # 计算需要的空格数来居中文本 + padding=$(( (COLUMNS - ${#line}) / 2 )) + printf "%${padding}s" '' + printf "${FLUORESCENT_YELLOW}${line}${NC}\n" + done <<< "$1" + } +fi + +############################# 17. download homotypic data ############################## +if [ true ]; then + data_path="data/indexing" + + print_orange "Data path: $data_path" + urls=( + "https://zenodo.org/record/8435321/files/Arabidopsis_thaliana.tar.gz" + "https://zenodo.org/record/8435321/files/Brachypodium_distachyon.tar.gz" + "https://zenodo.org/record/8435321/files/Brassica_napus.tar.gz" + "https://zenodo.org/record/8435321/files/Glycine_max.tar.gz" + "https://zenodo.org/record/8435321/files/Hordeum_vulgare_goldenpromise.tar.gz" + "https://zenodo.org/record/8435321/files/Hordeum_vulgare_Morex_V3.tar.gz" + "https://zenodo.org/record/8435321/files/Hordeum_vulgare_R1.tar.gz" + "https://zenodo.org/record/8435321/files/Hordeum_vulgare_v082214v1.tar.gz" + "https://zenodo.org/record/8435321/files/Medicago_truncatula.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_9311.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_IR8.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_MH63.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_ZS97.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Ensembl.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Kitaake.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Nipponbare.tar.gz" + "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_V7.1.tar.gz" + "https://zenodo.org/record/8435321/files/Solanum_lycopersicum.tar.gz" + "https://zenodo.org/record/8435321/files/Solanum_tuberosum.tar.gz" + "https://zenodo.org/record/8435321/files/Triticum_aestivum.tar.gz" + "https://zenodo.org/record/8435321/files/Zea_mays.tar.gz" + ) + + mkdir -p $data_path + # download and unzip + for url in "${urls[@]}"; do + filename=$(basename $url .tar.gz) + print_orange "Downloading homotypic motifs hits of ${filename//_/ }" + wget $url + tar -xzvf "$filename.tar.gz" -C data/indexing > /dev/null 2>&1 + rm "$filename.tar.gz" + done +fi diff --git a/scripts/glue_sys_reqs.R b/scripts/glue_sys_reqs.R new file mode 100644 index 0000000..2c1b71b --- /dev/null +++ b/scripts/glue_sys_reqs.R @@ -0,0 +1,42 @@ +glue_sys_reqs <- function(pkgs) { + rlang::check_installed("curl") + rspm = Sys.getenv("RSPM_ROOT", "https://packagemanager.rstudio.com") + rspm_repo_id = Sys.getenv("RSPM_REPO_ID", 1) + rspm_repo_url = glue::glue("{rspm}/__api__/repos/{rspm_repo_id}") + + pkgnames = glue::glue_collapse(unique(pkgs), sep = "&pkgname=") + + req_url = glue::glue( + "{rspm_repo_url}/sysreqs?all=false", + "&pkgname={pkgnames}&distribution=ubuntu&release=22.04" + ) + res = curl::curl_fetch_memory(req_url) + sys_reqs = jsonlite::fromJSON(rawToChar(res$content), simplifyVector = FALSE) + if (!is.null(sys_reqs$error)) rlang::abort(sys_reqs$error) + + sys_reqs = purrr::map(sys_reqs$requirements, purrr::pluck, "requirements", "packages") + sys_reqs = sort(unique(unlist(sys_reqs))) + sys_reqs = glue::glue_collapse(sys_reqs, sep = " \\\n ") + glue::glue( + "RUN apt-get update -qq && \\ \n", + " apt-get install -y --no-install-recommends \\\n ", + sys_reqs, + "\ && \\\n", + " apt-get clean && \\ \n", + " rm -rf /var/lib/apt/lists/*", + .trim = FALSE + ) +} + +# glue_sys_reqs(c("shiny", "dplyr")) +# #> RUN apt-get update -qq && \ +# #> apt-get install -y --no-install-recommends \ +# #> make \ +# #> zlib1g-dev && \ +# #> apt-get clean && \ +# #> rm -rf /var/lib/apt/lists/* + +# appdir = "app/" +# pkgs = renv::dependencies(appdir)$Package +# sys_reqs = glue_sys_reqs(pkgs) +# https://www.jumpingrivers.com/blog/shiny-auto-docker/ diff --git a/scripts/init_set_env.sh b/scripts/init_set_env.sh new file mode 100644 index 0000000..51125fb --- /dev/null +++ b/scripts/init_set_env.sh @@ -0,0 +1,13 @@ +#!/usr/bin/with-contenv bash +# shellcheck shell=bash + +## Set our dynamic variables in Renviron.site to be reflected by RStudio Server or Shiny Server +exclude_vars="HOME PASSWORD RSTUDIO_VERSION BATCH_USER_CREATION" +for file in /var/run/s6/container_environment/*; do + sed -i "/^${file##*/}=/d" "${R_HOME}/etc/Renviron.site" + regex="(^| )${file##*/}($| )" + [[ ! $exclude_vars =~ $regex ]] && echo "${file##*/}=$(cat "${file}")" >>"${R_HOME}/etc/Renviron.site" || echo "skipping ${file}" +done + +## only file-owner (root) should read container_environment files: +chmod 600 /var/run/s6/container_environment/* diff --git a/scripts/install_R_source.sh b/scripts/install_R_source.sh new file mode 100644 index 0000000..31460d8 --- /dev/null +++ b/scripts/install_R_source.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +## Install R from source. +## +## In order of preference, first argument of the script, the R_VERSION variable. +## ex. latest, devel, patched, 4.0.0 +## +## 'devel' means the prerelease development version (Latest daily snapshot of development version). +## 'patched' means the prerelease patched version (Latest daily snapshot of patched version). + +set -e + +R_VERSION=${1:-${R_VERSION:-"latest"}} +PURGE_BUILDDEPS=${PURGE_BUILDDEPS:-"true"} + +# shellcheck source=/dev/null +source /etc/os-release + +apt-get update +apt-get -y install locales + +## Configure default locale +LANG=${LANG:-"en_US.UTF-8"} +/usr/sbin/locale-gen --lang "${LANG}" +/usr/sbin/update-locale --reset LANG="${LANG}" + +export DEBIAN_FRONTEND=noninteractive + +R_HOME=${R_HOME:-"/usr/local/lib/R"} + +READLINE_VERSION=8 +if [ "${UBUNTU_CODENAME}" == "bionic" ]; then + READLINE_VERSION=7 +fi + +# libjpeg-turbo* \ +# libpangocairo-* \ +apt-get install -y --no-install-recommends \ + bash-completion \ + ca-certificates \ + file \ + fonts-texgyre \ + g++ \ + gfortran \ + gsfonts \ + libblas-dev \ + libbz2-* \ + libcurl4 \ + "libicu[0-9][0-9]" \ + liblapack-dev \ + libpcre2* \ + libpng16* \ + "libreadline${READLINE_VERSION}" \ + libtiff* \ + liblzma* \ + libxt6 \ + make \ + tzdata \ + unzip \ + zip \ + zlib1g + +# default-jdk \ +BUILDDEPS="curl \ + devscripts \ + libbz2-dev \ + libcairo2-dev \ + libcurl4-openssl-dev \ + libpango1.0-dev \ + libjpeg-dev \ + libicu-dev \ + libpcre2-dev \ + libpng-dev \ + libreadline-dev \ + libtiff5-dev \ + liblzma-dev \ + libx11-dev \ + libxt-dev \ + perl \ + rsync \ + subversion \ + tcl-dev \ + tk-dev \ + texinfo \ + texlive-extra-utils \ + texlive-fonts-recommended \ + texlive-fonts-extra \ + texlive-latex-recommended \ + texlive-latex-extra \ + x11proto-core-dev \ + xauth \ + xfonts-base \ + xvfb \ + wget \ + zlib1g-dev" + +# shellcheck disable=SC2086 +apt-get install -y --no-install-recommends ${BUILDDEPS} + +# ## Download R from 0-Cloud CRAN mirror or CRAN +function download_r_src() { + wget "https://cloud.r-project.org/src/$1" -O "R.tar.gz" || + wget "https://cran.r-project.org/src/$1" -O "R.tar.gz" || + wget "https://cran.rstudio.com/src/$1" -O "R.tar.gz" +} + +if [ "$R_VERSION" == "devel" ]; then + download_r_src "base-prerelease/R-devel.tar.gz" +elif [ "$R_VERSION" == "patched" ]; then + download_r_src "base-prerelease/R-latest.tar.gz" +elif [ "$R_VERSION" == "latest" ]; then + download_r_src "base/R-latest.tar.gz" +else + download_r_src "base/R-${R_VERSION%%.*}/R-${R_VERSION}.tar.gz" +fi + +tar xzf "R.tar.gz" +cd R-*/ + +R_PAPERSIZE=letter \ + R_BATCHSAVE="--no-save --no-restore" \ + R_BROWSER=xdg-open \ + PAGER=/usr/bin/pager \ + PERL=/usr/bin/perl \ + R_UNZIPCMD=/usr/bin/unzip \ + R_ZIPCMD=/usr/bin/zip \ + R_PRINTCMD=/usr/bin/lpr \ + LIBnn=lib \ + AWK=/usr/bin/awk \ + CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g" \ + CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g" \ + ./configure --enable-R-shlib \ + --enable-memory-profiling \ + --with-readline \ + --with-blas \ + --with-lapack \ + --with-tcltk \ + --with-recommended-packages + +make +make install +make clean + +## Add a library directory (for user-installed packages) +mkdir -p "${R_HOME}/site-library" +chown root:staff "${R_HOME}/site-library" +chmod g+ws "${R_HOME}/site-library" + +## Fix library path +echo "R_LIBS=\${R_LIBS-'${R_HOME}/site-library:${R_HOME}/library'}" >>"${R_HOME}/etc/Renviron.site" + +## Clean up from R source install +cd .. +rm -rf /tmp/* +rm -rf R-*/ +rm -rf "R.tar.gz" + +## Copy the checkbashisms script to local before remove devscripts package. +## https://github.com/rocker-org/rocker-versioned2/issues/510 +cp /usr/bin/checkbashisms /usr/local/bin/checkbashisms + +# shellcheck disable=SC2086 +if [ "${PURGE_BUILDDEPS}" != "false" ]; then + apt-get remove --purge -y ${BUILDDEPS} +fi +apt-get autoremove -y +apt-get autoclean -y +rm -rf /var/lib/apt/lists/* + +# Check the R info +echo -e "Check the R info...\n" + +R -q -e "sessionInfo()" + +echo -e "\nInstall R from source, done!" diff --git a/scripts/install_apt_tools.sh b/scripts/install_apt_tools.sh new file mode 100644 index 0000000..1dcfeb7 --- /dev/null +++ b/scripts/install_apt_tools.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +set -e + +apt update && apt upgrade -y + +# update-alternatives --config libblas.so.3-$(arch)-linux-gnu +echo "deb http://security.ubuntu.com/ubuntu focal-security main" | tee /etc/apt/sources.list.d/focal-security.list + +apt -y install libcurl4-openssl-dev +apt -y install curl +apt -y install vim +apt -y install wget bzip2 +apt -y install openjdk-21-jdk +apt -y install r-cran-rjava +apt -y install build-essential + +apt -y install autotools-dev +apt -y install automake +apt -y install nodejs +apt -y install libssl-dev +apt -y install libxml2-dev +apt -y install libxml2 +apt -y install cmake +apt -y install libharfbuzz-dev +apt -y install libfribidi-dev +apt -y install libncurses5-dev +apt -y install libncursesw5-dev +apt -y install libbz2-dev +apt -y install parallel +apt -y install ufw + +apt -y install libjpeg-dev +apt -y install librsvg2-dev +apt -y install libpoppler-cpp-dev +apt -y install freetype2-demos +apt -y install cargo +apt -y install libxslt-dev +apt -y install zlib1g-dev +apt -y install libgdbm-dev +apt -y install npm +apt -y install libtesseract-dev +apt -y install libleptonica-dev +apt -y install tesseract-ocr-eng +apt -y install libmagick++-dev +apt -y install libavfilter-dev +apt -y install zip +apt -y install libpcre2-dev +apt -y install libreadline-dev +apt -y install glibc-source +apt -y install libstdc++6 +apt -y install genometools +# apt -y install libssl1.1 +apt -y install libopenblas-dev +apt -y install gfortran + +apt -y install rsync + +wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb +sudo dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb +rm libssl1.1_1.1.0g-2ubuntu4_amd64.deb + +export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java)))) +export PATH=$PATH:$JAVA_HOME/bin + +apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/scripts/install_pandoc.sh b/scripts/install_pandoc.sh new file mode 100644 index 0000000..9f19071 --- /dev/null +++ b/scripts/install_pandoc.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +## Install pandoc or symlinks pandoc, pandoc-citeproc so they are available system-wide. +## +## In order of preference, first argument of the script, the PANDOC_VERSION variable. +## ex. latest, default +## +## 'default' means the version bundled with RStudio if RStudio is installed, but 'latest' otherwise. +## 'latest' means installing the latest release version. + +set -e + +PANDOC_VERSION=${1:-${PANDOC_VERSION:-"default"}} +ARCH=$(dpkg --print-architecture) + +# a function to install apt packages only if they are not installed +function apt_install() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + apt-get install -y --no-install-recommends "$@" + fi +} + +apt_install wget ca-certificates + +if [ -x "$(command -v pandoc)" ]; then + INSTALLED_PANDOC_VERSION=$(pandoc --version 2>/dev/null | head -n 1 | grep -oP '[\d\.]+$') +fi + +if [ -f "/usr/lib/rstudio-server/bin/pandoc/pandoc" ]; then + BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/pandoc/pandoc" +elif [ -f "/usr/lib/rstudio-server/bin/quarto/bin/pandoc" ]; then + BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/quarto/bin/pandoc" +elif [ -f "/usr/lib/rstudio-server/bin/quarto/bin/tools/pandoc" ]; then + BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/quarto/bin/tools/pandoc" +fi + +if [ -n "$BUNDLED_PANDOC" ]; then + BUNDLED_PANDOC_VERSION="$($BUNDLED_PANDOC --version | head -n 1 | grep -oP '[\d\.]+$')" +fi + +if [ "$PANDOC_VERSION" != "$INSTALLED_PANDOC_VERSION" ]; then + + if [ "$PANDOC_VERSION" = "default" ] && [ -z "$BUNDLED_PANDOC" ]; then + PANDOC_VERSION="latest" + fi + + if [ "$PANDOC_VERSION" = "$BUNDLED_PANDOC_VERSION" ] || [ "$PANDOC_VERSION" = "default" ]; then + ln -fs "$BUNDLED_PANDOC" /usr/local/bin + if [ -f "${BUNDLED_PANDOC}-citeproc" ]; then + ln -fs "${BUNDLED_PANDOC}-citeproc" /usr/local/bin + fi + else + if [ -L "/usr/local/bin/pandoc" ]; then + unlink /usr/local/bin/pandoc + fi + if [ -L "/usr/local/bin/pandoc-citeproc" ]; then + unlink /usr/local/bin/pandoc-citeproc + fi + + if [ "$PANDOC_VERSION" = "latest" ]; then + PANDOC_DL_URL=$(wget -qO- https://api.github.com/repos/jgm/pandoc/releases/latest | grep -oP "(?<=\"browser_download_url\":\s\")https.*${ARCH}\.deb") + else + PANDOC_DL_URL="https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-1-${ARCH}.deb" + fi + wget "$PANDOC_DL_URL" -O pandoc.deb + dpkg -i pandoc.deb + rm pandoc.deb + fi + + ## Symlink pandoc & standard pandoc templates for use system-wide + PANDOC_TEMPLATES_VERSION=$(pandoc -v | grep -oP "(?<=pandoc\s)[0-9\.]+$") + wget "https://github.com/jgm/pandoc-templates/archive/${PANDOC_TEMPLATES_VERSION}.tar.gz" -O pandoc-templates.tar.gz + rm -fr /opt/pandoc/templates + mkdir -p /opt/pandoc/templates + tar xvf pandoc-templates.tar.gz + cp -r pandoc-templates*/* /opt/pandoc/templates && rm -rf pandoc-templates* + rm -fr /root/.pandoc + mkdir /root/.pandoc && ln -s /opt/pandoc/templates /root/.pandoc/templates +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Check the pandoc version +echo -e "Check the pandoc version...\n" +pandoc --version +echo -e "\nInstall pandoc, done!" diff --git a/scripts/install_python.sh b/scripts/install_python.sh new file mode 100644 index 0000000..373b6bd --- /dev/null +++ b/scripts/install_python.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -e + +## build ARGs +NCPUS=${NCPUS:--1} + +# a function to install apt packages only if they are not installed +function apt_install() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + apt-get install -y --no-install-recommends "$@" + fi +} + +apt_install \ + libpng-dev \ + libpython3-dev \ + python3-dev \ + python3-pip \ + python3-venv \ + swig + +# Setup a virtualenv to install things into + +# Put things under /opt/venv, if nothing else is specified +export VIRTUAL_ENV="${VIRTUAL_ENV:=/opt/venv}" +export PATH="${VIRTUAL_ENV}/bin:${PATH}" + +# Make sure that Rstudio sees these env vars too +echo "PATH=${PATH}" >>"${R_HOME}/etc/Renviron.site" +echo "VIRTUAL_ENV=${VIRTUAL_ENV}" >>"${R_HOME}/etc/Renviron.site" + +python3 -m venv "${VIRTUAL_ENV}" + +# Upgrade version of pip inside the virtualenv +python3 -m pip --no-cache-dir install --upgrade \ + pip + +# Make the venv owned by the staff group, so users can install packages +# without having to be root +chown -R root:staff "${VIRTUAL_ENV}" +chmod -R g+ws "${VIRTUAL_ENV}" + +scripts/bin/install2.r --error --skipmissing --skipinstalled -n "$NCPUS" reticulate + +# Clean up +rm -rf /var/lib/apt/lists/* +rm -rf /tmp/downloaded_packages + +## Strip binary installed lybraries from RSPM +## https://github.com/rocker-org/rocker-versioned2/issues/340 +strip /usr/local/lib/R/library/*/libs/*.so + +## Don't use OpenBLAS with reticulate on Ubuntu 20.04 +## https://github.com/rocker-org/rocker-versioned2/issues/471 +source /etc/os-release +if [ "${UBUNTU_CODENAME}" == "focal" ]; then + if R -q -e 'sessionInfo()' | grep -q openblas; then + ARCH=$(uname -m) + echo "Switching BLAS (Details: https://github.com/rocker-org/rocker-versioned2/issues/471)" + update-alternatives --set "libblas.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/blas/libblas.so.3" + update-alternatives --set "liblapack.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/lapack/liblapack.so.3" + fi +fi + +# Check that python and python3 point to correct places +echo "Check python, python3 and pip executables point to the correct place..." +echo "python -> $(which python)" +echo "python3 -> $(which python3)" +echo "pip -> $(which pip)" + +# Check Python version +echo -e "Check the Python to use with reticulate...\n" + +R -q -e 'reticulate::py_discover_config(required_module = NULL, use_environment = NULL)' + +echo -e "\nInstall Python, done!" diff --git a/scripts/install_python_libs.sh b/scripts/install_python_libs.sh new file mode 100644 index 0000000..8ea9ed8 --- /dev/null +++ b/scripts/install_python_libs.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +pip3 install leidenalg +pip3 install python-igraph +pip3 install numpy +pip3 install pandas +# pip3 install scipy +python3 -m pip install scipy +pip3 install bio +pip3 install biopython diff --git a/scripts/install_s6init.sh b/scripts/install_s6init.sh new file mode 100644 index 0000000..475c388 --- /dev/null +++ b/scripts/install_s6init.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -e + +### Sets up S6 supervisor. + +S6_VERSION=${1:-${S6_VERSION:-"v2.1.0.2"}} + +# a function to install apt packages only if they are not installed +function apt_install() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + apt-get install -y --no-install-recommends "$@" + fi +} + +ARCH=$(dpkg --print-architecture) + +if [ "$ARCH" = "arm64" ]; then + ARCH=aarch64 +fi + +DOWNLOAD_FILE=s6-overlay-${ARCH}.tar.gz + +apt_install wget ca-certificates + +## Set up S6 init system +if [ -f "scripts/.s6_version" ] && [ "$S6_VERSION" = "$(cat scripts/.s6_version)" ]; then + echo "S6 already installed" +else + wget -P /tmp/ "https://github.com/just-containers/s6-overlay/releases/download/${S6_VERSION}/${DOWNLOAD_FILE}" + + ## need the modified double tar now, see https://github.com/just-containers/s6-overlay/issues/288 + tar hzxf /tmp/$DOWNLOAD_FILE -C / --exclude=usr/bin/execlineb + tar hzxf /tmp/$DOWNLOAD_FILE -C /usr ./bin/execlineb + + echo "$S6_VERSION" > scripts/.s6_version +fi + +# Clean up +rm -rf /var/lib/apt/lists/* +rm -f /tmp/$DOWNLOAD_FILE diff --git a/scripts/install_shiny_server.sh b/scripts/install_shiny_server.sh new file mode 100644 index 0000000..fd1e56c --- /dev/null +++ b/scripts/install_shiny_server.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -e + +SHINY_SERVER_VERSION=${1:-${SHINY_SERVER_VERSION:-latest}} + +## build ARGs +NCPUS=${NCPUS:--1} + +# a function to install apt packages only if they are not installed +function apt_install() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + apt-get install -y --no-install-recommends "$@" + fi +} + +apt_install \ + sudo \ + gdebi-core \ + lsb-release \ + libcurl4-openssl-dev \ + libcairo2-dev \ + libxt-dev \ + xtail \ + wget + +# Run dependency scripts +scripts/install_s6init.sh +scripts/install_pandoc.sh + +# Install Shiny server + +if [ "$SHINY_SERVER_VERSION" = "latest" ]; then + SHINY_SERVER_VERSION=$(wget -qO- https://download3.rstudio.org/ubuntu-18.04/x86_64/VERSION) +fi + +wget --no-verbose "https://download3.rstudio.org/ubuntu-18.04/x86_64/shiny-server-${SHINY_SERVER_VERSION}-amd64.deb" -O ss-latest.deb +gdebi -n ss-latest.deb +rm ss-latest.deb + +# Get R packages +scripts/bin/install2.r --error --skipinstalled -n "$NCPUS" shiny rmarkdown + +# Set up directories and permissions +if [ -x "$(command -v rstudio-server)" ]; then + DEFAULT_USER=${DEFAULT_USER:-rstudio} + adduser "${DEFAULT_USER}" shiny +fi + +cp -R /usr/local/lib/R/library/shiny/examples/* /srv/shiny-server/ +chown shiny:shiny /var/lib/shiny-server +mkdir -p /var/log/shiny-server +chown shiny:shiny /var/log/shiny-server + +# create init scripts +mkdir -p /etc/services.d/shiny-server +cat <<"EOF" >/etc/services.d/shiny-server/run +#!/usr/bin/with-contenv bash +## load /etc/environment vars first: +for line in $( cat /etc/environment ) ; do export $line > /dev/null; done +if [ "$APPLICATION_LOGS_TO_STDOUT" != "false" ]; then + exec xtail /var/log/shiny-server/ & +fi +exec shiny-server 2>&1 +EOF +chmod +x /etc/services.d/shiny-server/run + +# install init script +cp scripts/init_set_env.sh /etc/cont-init.d/01_set_env + +# Clean up +rm -rf /var/lib/apt/lists/* +rm -rf /tmp/downloaded_packages + +## Strip binary installed lybraries from RSPM +## https://github.com/rocker-org/rocker-versioned2/issues/340 +strip /usr/local/lib/R/library/*/libs/*.so diff --git a/scripts/setup_R.sh b/scripts/setup_R.sh new file mode 100644 index 0000000..3ec5b7e --- /dev/null +++ b/scripts/setup_R.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +## Update configuration files for R and install some libraries. +## +## The URL of the default repository for R packages written to Rprofile.site, +## refers to the CRAN environment variable or to the first argument of this script. +## In order of preference, first argument of the script, the CRAN variable. +## ex. https://cloud.r-project.org, https://cran.r-project.org + +set -e + +CRAN=${1:-${CRAN:-"https://cran.r-project.org"}} +PURGE_BUILDDEPS=${PURGE_BUILDDEPS:-"true"} + +ARCH=$(uname -m) + +# shellcheck source=/dev/null +source /etc/os-release + +# a function to install apt packages only if they are not installed +function apt_install() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + apt-get install -y --no-install-recommends "$@" + fi +} + +## mechanism to force source installs if we're using RSPM +CRAN_SOURCE=${CRAN/"__linux__/${UBUNTU_CODENAME}/"/""} + +## source install if using RSPM and arm64 image +if [ "$ARCH" = "aarch64" ]; then + CRAN=$CRAN_SOURCE +fi + +## Add a default CRAN mirror +echo "options(repos = c(CRAN = '${CRAN}'), download.file.method = 'libcurl')" >>"${R_HOME}/etc/Rprofile.site" + +## Set HTTPUserAgent for RSPM (https://github.com/rocker-org/rocker/issues/400) +cat <>"${R_HOME}/etc/Rprofile.site" +# https://docs.rstudio.com/rspm/admin/serving-binaries/#binaries-r-configuration-linux +options(HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste(getRversion(), R.version["platform"], R.version["arch"], R.version["os"]))) +EOF + +## Install OpenBLAS and hot-switching to it +## https://github.com/rocker-org/rocker-versioned2/issues/390 +if ! dpkg -l | grep -q libopenblas-dev; then + apt_install libopenblas-dev + update-alternatives --set "libblas.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/openblas-pthread/libblas.so.3" +fi + +## Install littler +if [ ! -x "$(command -v r)" ]; then + BUILDDEPS="libpcre2-dev \ + libdeflate-dev \ + liblzma-dev \ + libbz2-dev \ + zlib1g-dev \ + libicu-dev" + + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + apt-get update + fi + # shellcheck disable=SC2086 + apt_install ${BUILDDEPS} + Rscript -e "install.packages(c('littler', 'docopt'), repos='${CRAN_SOURCE}')" + + # Clean up + # shellcheck disable=SC2086 + if [ "${PURGE_BUILDDEPS}" != "false" ]; then + apt-get remove --purge -y ${BUILDDEPS} + fi + apt-get autoremove -y + apt-get autoclean -y +fi + +## Symlink littler and littler's installation scripts +ln -sf "${R_HOME}/site-library/littler/bin/r" /usr/local/bin/r +ln -sf "${R_HOME}/site-library/littler/examples/installGithub.r" /usr/local/bin/installGithub.r + +## Use rocker scripts version install2.r if it exists +if [ -f "scripts/bin/install2.r" ]; then + ln -sf scripts/bin/install2.r /usr/local/bin/install2.r +else + ln -sf "${R_HOME}/site-library/littler/examples/install2.r" /usr/local/bin/install2.r +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Check the R info +echo -e "Check the littler info...\n" + +R --version + +echo -e "Check the R info...\n" + +R -q -e "sessionInfo()" + +echo -e "Setup R, done!" diff --git a/scripts/shiny-server.sh b/scripts/shiny-server.sh new file mode 100644 index 0000000..f1b0877 --- /dev/null +++ b/scripts/shiny-server.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# # Make sure the directory for individual app logs exists +# mkdir -p /var/log/shiny-server +# chown shiny.shiny /var/log/shiny-server + +exec shiny-server >> /var/log/shiny-server/shiny-server.log 2>&1 diff --git a/www/shiny.css b/www/shiny.css index f4fac19..0ae40a6 100644 --- a/www/shiny.css +++ b/www/shiny.css @@ -352,3 +352,4 @@ text.text-hover { .tab-pane { margin-top: 5px; } +