From 8f57176d95122d9f47f6f351dcfd0026196593d4 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 14:30:42 +0200 Subject: [PATCH 1/8] Universal version of installation script including special feuters for container installation --- install_vivid_volcano.sh | 1107 ++++++++++++++++++-------------------- 1 file changed, 520 insertions(+), 587 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index ae2a334..f6133f7 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -1,13 +1,14 @@ #!/bin/bash # ==================================================================== -# Vivid Volcano - Core Installation Script (PostgreSQL-free) +# Vivid Volcano - Universal Installation Script # ==================================================================== # Author: DatViseR -# Date: 2025-06-21 -# Description: Clones Vivid Volcano repository, sets up core renv environment and runs the application +# Date: 2025-07-07 +# Description: Universal installation for local and cloud environments # Repository: https://github.com/DatViseR/Vivid-Volcano -# ==================================================================== +# Works on: macOS, Linux, Codespaces, Gitpod, and other containers +# ==================================================================== set -e # Exit on any error @@ -64,8 +65,18 @@ check_r_version() { fi } -detect_os() { - if [[ "$OSTYPE" == "linux-gnu"* ]]; then +detect_environment() { + # Cloud environments + if [[ -n "${CODESPACE_NAME:-}" ]] || [[ -n "${GITHUB_CODESPACES:-}" ]]; then + echo "codespaces" + elif [[ -n "${GITPOD_WORKSPACE_ID:-}" ]]; then + echo "gitpod" + elif [[ -n "${COLAB_GPU:-}" ]]; then + echo "colab" + elif [[ -n "${JUPYTER_SERVER_ROOT:-}" ]]; then + echo "jupyter" + # Local environments + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then if command_exists lsb_release; then echo $(lsb_release -si | tr '[:upper:]' '[:lower:]') elif [[ -f /etc/os-release ]]; then @@ -82,209 +93,315 @@ detect_os() { fi } -# Essential system dependencies (minimal set) -install_essential_dependencies() { - print_header "INSTALLING ESSENTIAL SYSTEM DEPENDENCIES" +is_container_environment() { + local env=$(detect_environment) + case $env in + codespaces|gitpod|colab|jupyter) + return 0 + ;; + *) + # Additional container detection + if [[ -f /.dockerenv ]] || [[ -f /run/.containerenv ]]; then + return 0 + fi + return 1 + ;; + esac +} + +# Auto-install missing prerequisites +auto_install_prerequisites() { + print_header "CHECKING AND INSTALLING PREREQUISITES" + + local env=$(detect_environment) + print_info "Detected environment: $env" + + local need_r=false + local need_git=false + + # Check what's missing + if ! command_exists git; then + need_git=true + print_warning "Git is not installed" + fi + + if ! command_exists R; then + need_r=true + print_warning "R is not installed" + fi + + # Auto-install for supported environments + if [[ "$need_git" == true ]] || [[ "$need_r" == true ]]; then + case $env in + codespaces|ubuntu|debian|gitpod) + if command_exists apt-get; then + print_step "Auto-installing prerequisites for $env..." + + # Update package list with proper error handling + print_info "Updating package list..." + sudo apt-get update -qq || { + print_warning "Package list update failed, but continuing..." + } + + local packages_to_install=() + + if [[ "$need_git" == true ]]; then + packages_to_install+=("git") + fi + + if [[ "$need_r" == true ]]; then + packages_to_install+=("r-base" "r-base-dev") + fi + + if [[ ${#packages_to_install[@]} -gt 0 ]]; then + print_info "Installing: ${packages_to_install[*]}" + + # Install with better error handling to prevent freezing + timeout 300 sudo apt-get install -y "${packages_to_install[@]}" || { + print_error "Auto-installation failed or timed out" + print_info "Please install manually:" + [[ "$need_git" == true ]] && print_info " sudo apt-get install git" + [[ "$need_r" == true ]] && print_info " sudo apt-get install r-base r-base-dev" + return 1 + } + + print_success "Prerequisites auto-installed successfully" + fi + fi + ;; + fedora|centos|rhel) + if command_exists dnf; then + print_step "Auto-installing prerequisites for $env..." + local packages_to_install=() + + if [[ "$need_git" == true ]]; then + packages_to_install+=("git") + fi + + if [[ "$need_r" == true ]]; then + packages_to_install+=("R" "R-devel") + fi + + if [[ ${#packages_to_install[@]} -gt 0 ]]; then + sudo dnf install -y "${packages_to_install[@]}" || { + print_warning "Some packages failed to install" + } + fi + fi + ;; + macos) + print_info "macOS detected - please install missing prerequisites manually:" + [[ "$need_git" == true ]] && print_info " Git: Install Xcode Command Line Tools" + [[ "$need_r" == true ]] && print_info " R: Download from https://cran.r-project.org/" + return 1 + ;; + *) + print_warning "Cannot auto-install on $env environment" + print_info "Please install missing prerequisites manually" + return 1 + ;; + esac + fi + + return 0 +} + +# Enhanced system library detection +check_system_library() { + local lib_name="$1" + local header_file="$2" + local pkg_config_name="$3" + + # Method 1: Check via pkg-config + if command_exists pkg-config && [[ -n "$pkg_config_name" ]]; then + if pkg-config --exists "$pkg_config_name" 2>/dev/null; then + return 0 + fi + fi + + # Method 2: Check for header file + if [[ -n "$header_file" ]]; then + local search_paths=( + "/usr/include" + "/usr/local/include" + "/opt/homebrew/include" + "/opt/local/include" + "/usr/include/x86_64-linux-gnu" + ) + + for path in "${search_paths[@]}"; do + if [[ -f "$path/$header_file" ]]; then + return 0 + fi + done + fi + + # Method 3: OS-specific checks + local env=$(detect_environment) + case $env in + macos) + if command_exists brew && brew list "$lib_name" &>/dev/null; then + return 0 + fi + ;; + ubuntu|debian|codespaces|gitpod) + if dpkg -l | grep -q "lib${lib_name}.*-dev"; then + return 0 + fi + ;; + fedora|centos|rhel) + if rpm -qa | grep -q "${lib_name}.*-devel"; then + return 0 + fi + ;; + esac + + return 1 +} + +# Enhanced dependency installation with individual choice +install_enhanced_dependencies() { + print_header "SYSTEM DEPENDENCIES INSTALLATION" - local os=$(detect_os) - print_info "Detected OS: $os" + local env=$(detect_environment) + print_info "Environment: $env" - case $os in - ubuntu|debian) - print_step "Available Ubuntu/Debian dependencies" + case $env in + ubuntu|debian|codespaces|gitpod) if command_exists apt-get; then - print_info "Updating package list..." - sudo apt-get update -qq + print_step "Available Ubuntu/Debian dependencies" + sudo apt-get update -qq || print_warning "Package update failed" - # Define packages with descriptions - declare -A packages_desc=( - ["libssl-dev"]="SSL library - Required for secure connections (openssl, httr packages)" - ["libcurl4-openssl-dev"]="cURL library - Required for HTTP requests (curl, httr packages)" + # Core dependencies (always install) + local core_packages=("libssl-dev" "libcurl4-openssl-dev") + print_info "Installing core dependencies: ${core_packages[*]}" + sudo apt-get install -y "${core_packages[@]}" || { + print_error "Failed to install core dependencies" + exit 1 + } + + # Optional dependencies with descriptions + declare -A optional_packages=( ["libxml2-dev"]="XML library - Optional for XML processing (xml2 package)" - ["libfontconfig1-dev"]="Font configuration - Optional for advanced text rendering" - ["libcairo2-dev"]="Cairo graphics - Optional for high-quality graphics output" + ["libfontconfig1-dev"]="Font configuration - Optional for text rendering" + ["libcairo2-dev"]="Cairo graphics - Optional for high-quality graphics" ["libharfbuzz-dev"]="Text shaping - Optional for complex text layout" - ["libfribidi-dev"]="Bidirectional text - Optional for right-to-left text support" - ["libfreetype6-dev"]="Font rendering - Optional for custom font support" - ["libpng-dev"]="PNG support - Optional for PNG image processing" - ["libjpeg-dev"]="JPEG support - Optional for JPEG image processing" + ["libfribidi-dev"]="Bidirectional text - Optional for right-to-left text" + ["libfreetype6-dev"]="Font rendering - Optional for custom fonts" + ["libpng-dev"]="PNG support - Optional for PNG processing" + ["libjpeg-dev"]="JPEG support - Optional for JPEG processing" ) - local packages_to_install=() + local selected_packages=() echo - print_info "Please choose which dependencies to install:" - echo - - for package in "${!packages_desc[@]}"; do - echo -e "${CYAN}Package:${NC} ${package}" - echo -e "${YELLOW}Description:${NC} ${packages_desc[$package]}" - read -p "Install $package? (Y/n): " -n 1 -r + print_info "Optional dependencies (choose individually):" + for pkg in "${!optional_packages[@]}"; do + echo -e "${CYAN}Package:${NC} $pkg" + echo -e "${YELLOW}Description:${NC} ${optional_packages[$pkg]}" + read -p "Install $pkg? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then - packages_to_install+=("$package") - echo -e "${GREEN}✓ Will install $package${NC}" + selected_packages+=("$pkg") + echo -e "${GREEN}✓ Will install $pkg${NC}" else - echo -e "${YELLOW}⚬ Skipping $package${NC}" + echo -e "${YELLOW}⚬ Skipping $pkg${NC}" fi echo done - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - print_info "Installing selected packages: ${packages_to_install[*]}" - sudo apt-get install -y "${packages_to_install[@]}" || { - print_warning "Some packages failed to install, but continuing with core installation..." + if [[ ${#selected_packages[@]} -gt 0 ]]; then + print_info "Installing selected packages: ${selected_packages[*]}" + sudo apt-get install -y "${selected_packages[@]}" || { + print_warning "Some optional packages failed to install" } - print_success "Selected dependencies installation completed" - else - print_info "No packages selected for installation" fi - else - print_warning "apt-get not found, skipping system dependencies" fi ;; fedora|centos|rhel) - print_step "Available Red Hat/Fedora dependencies" if command_exists dnf; then - # Define packages with descriptions - declare -A packages_desc=( - ["openssl-devel"]="SSL library - Required for secure connections (openssl, httr packages)" - ["libcurl-devel"]="cURL library - Required for HTTP requests (curl, httr packages)" - ["libxml2-devel"]="XML library - Optional for XML processing (xml2 package)" - ["fontconfig-devel"]="Font configuration - Optional for advanced text rendering" - ["cairo-devel"]="Cairo graphics - Optional for high-quality graphics output" - ["harfbuzz-devel"]="Text shaping - Optional for complex text layout" - ["fribidi-devel"]="Bidirectional text - Optional for right-to-left text support" - ["freetype-devel"]="Font rendering - Optional for custom font support" - ["libpng-devel"]="PNG support - Optional for PNG image processing" - ["libjpeg-turbo-devel"]="JPEG support - Optional for JPEG image processing" - ) - - local packages_to_install=() + local core_packages=("openssl-devel" "libcurl-devel") + print_info "Installing core dependencies: ${core_packages[*]}" + sudo dnf install -y "${core_packages[@]}" - echo - print_info "Please choose which dependencies to install:" - echo - - for package in "${!packages_desc[@]}"; do - echo -e "${CYAN}Package:${NC} ${package}" - echo -e "${YELLOW}Description:${NC} ${packages_desc[$package]}" - read -p "Install $package? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - packages_to_install+=("$package") - echo -e "${GREEN}✓ Will install $package${NC}" - else - echo -e "${YELLOW}⚬ Skipping $package${NC}" - fi - echo - done - - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - print_info "Installing selected packages: ${packages_to_install[*]}" - sudo dnf install -y "${packages_to_install[@]}" || { - print_warning "Some packages failed to install, but continuing..." - } - print_success "Selected dependencies installation completed" - else - print_info "No packages selected for installation" - fi - elif command_exists yum; then - print_info "Using yum package manager - installing essential packages only" - declare -A packages_desc=( - ["openssl-devel"]="SSL library - Required for secure connections" - ["libcurl-devel"]="cURL library - Required for HTTP requests" - ["libxml2-devel"]="XML library - Optional for XML processing" + declare -A optional_packages=( + ["libxml2-devel"]="XML2 library" + ["fontconfig-devel"]="Font configuration" + ["cairo-devel"]="Cairo graphics" + ["harfbuzz-devel"]="Text shaping" + ["fribidi-devel"]="Bidirectional text" + ["freetype-devel"]="Font rendering" + ["libpng-devel"]="PNG support" + ["libjpeg-turbo-devel"]="JPEG support" ) - local packages_to_install=() - + # Similar selection process for optional packages + local selected_packages=() echo - for package in "${!packages_desc[@]}"; do - echo -e "${CYAN}Package:${NC} ${package}" - echo -e "${YELLOW}Description:${NC} ${packages_desc[$package]}" - read -p "Install $package? (Y/n): " -n 1 -r + for pkg in "${!optional_packages[@]}"; do + echo -e "${CYAN}Package:${NC} $pkg - ${optional_packages[$pkg]}" + read -p "Install $pkg? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then - packages_to_install+=("$package") - echo -e "${GREEN}✓ Will install $package${NC}" - else - echo -e "${YELLOW}⚬ Skipping $package${NC}" + selected_packages+=("$pkg") fi - echo done - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - sudo yum install -y "${packages_to_install[@]}" || { - print_warning "Some packages failed to install, but continuing..." - } + if [[ ${#selected_packages[@]} -gt 0 ]]; then + sudo dnf install -y "${selected_packages[@]}" fi - else - print_warning "Neither dnf nor yum found, skipping system dependencies" fi ;; macos) - print_step "Available macOS dependencies (via Homebrew)" if command_exists brew; then - declare -A packages_desc=( - ["openssl"]="SSL library - Required for secure connections (openssl, httr packages)" - ["curl"]="cURL library - Required for HTTP requests (curl, httr packages)" - ["libxml2"]="XML library - Optional for XML processing (xml2 package)" - ["cairo"]="Cairo graphics - Optional for high-quality graphics output" - ["harfbuzz"]="Text shaping - Optional for complex text layout" - ["fribidi"]="Bidirectional text - Optional for right-to-left text support" - ["freetype"]="Font rendering - Optional for custom font support" - ["libpng"]="PNG support - Optional for PNG image processing" - ["jpeg"]="JPEG support - Optional for JPEG image processing" - ) + local core_packages=("openssl" "curl") + print_info "Installing core dependencies: ${core_packages[*]}" + brew install "${core_packages[@]}" - local packages_to_install=() + declare -A optional_packages=( + ["libxml2"]="XML2 library" + ["cairo"]="Cairo graphics" + ["harfbuzz"]="Text shaping" + ["fribidi"]="Bidirectional text" + ["freetype"]="Font rendering" + ["libpng"]="PNG support" + ["jpeg"]="JPEG support" + ) + # Similar selection process + local selected_packages=() echo - print_info "Please choose which dependencies to install:" - echo - - for package in "${!packages_desc[@]}"; do - echo -e "${CYAN}Package:${NC} ${package}" - echo -e "${YELLOW}Description:${NC} ${packages_desc[$package]}" - read -p "Install $package? (Y/n): " -n 1 -r + for pkg in "${!optional_packages[@]}"; do + echo -e "${CYAN}Package:${NC} $pkg - ${optional_packages[$pkg]}" + read -p "Install $pkg? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then - packages_to_install+=("$package") - echo -e "${GREEN}✓ Will install $package${NC}" - else - echo -e "${YELLOW}⚬ Skipping $package${NC}" + selected_packages+=("$pkg") fi - echo done - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - print_info "Installing selected packages: ${packages_to_install[*]}" - brew install "${packages_to_install[@]}" || { - print_warning "Some packages failed to install, but continuing..." - } - print_success "Selected dependencies installation completed" - else - print_info "No packages selected for installation" + if [[ ${#selected_packages[@]} -gt 0 ]]; then + brew install "${selected_packages[@]}" fi else - print_warning "Homebrew not found. Install Homebrew first: https://brew.sh" + print_warning "Homebrew not found. Install from: https://brew.sh" fi ;; - - *) - print_warning "Unknown OS: $os - skipping system dependencies" - print_info "You may need to install development libraries manually if needed" - ;; esac } -# Prerequisites check +# Prerequisites check with auto-installation check_prerequisites() { print_header "CHECKING PREREQUISITES" + # Attempt auto-installation first + auto_install_prerequisites || { + print_warning "Auto-installation failed or not supported" + print_info "Continuing with manual prerequisite check..." + } + local missing_deps=() # Check Git @@ -295,20 +412,25 @@ check_prerequisites() { print_success "Git found: $(git --version)" fi - # Check R + # Check R with better error handling if ! command_exists R; then missing_deps+=("R") print_error "R is not installed" else - local r_version=$(R --version | head -n1) - print_success "R found: $r_version" + # Safer R version check + local r_version_output + r_version_output=$(timeout 10 R --version 2>/dev/null | head -n1) || { + print_warning "Could not determine R version (R may be installed but not responding)" + r_version_output="R (version check failed)" + } + print_success "R found: $r_version_output" - if ! check_r_version; then + if ! check_r_version 2>/dev/null; then print_warning "R version should be 4.4+ for optimal compatibility" fi fi - # Check available disk space (minimum 2GB) + # Check disk space local available_space=$(df . | tail -1 | awk '{print $4}') local space_gb=$((available_space / 1024 / 1024)) @@ -319,11 +441,16 @@ check_prerequisites() { fi # Check internet connectivity - if curl -s 1 github.com >/dev/null 2>&1; then + if ping -c 1 github.com >/dev/null 2>&1; then print_success "Internet connectivity confirmed" else - missing_deps+=("internet") - print_error "No internet connectivity to GitHub" + # Don't fail in container environments + if is_container_environment; then + print_warning "Limited internet connectivity detected (common in containers)" + else + missing_deps+=("internet") + print_error "No internet connectivity to GitHub" + fi fi if [[ ${#missing_deps[@]} -gt 0 ]]; then @@ -335,7 +462,7 @@ check_prerequisites() { print_success "All prerequisites satisfied" } -# Clone or update repository +# Repository setup (unchanged) setup_repository() { print_header "SETTING UP REPOSITORY" @@ -385,13 +512,14 @@ setup_repository() { print_info "Current directory: $(pwd)" } -# Core renv environment setup without problematic packages -setup_core_renv_environment() { - print_header "SETTING UP CORE RENV ENVIRONMENT" +# Enhanced renv setup with dependency-aware installation +setup_enhanced_renv_environment() { + print_header "SETTING UP R ENVIRONMENT" - print_step "Installing renv globally (if needed)" + print_step "Installing renv package manager" - R --slave --no-restore --no-save -e " + # Install renv with timeout to prevent freezing + timeout 120 R --slave --no-restore --no-save -e " if (!requireNamespace('renv', quietly = TRUE)) { cat('Installing renv globally...\n') install.packages('renv', repos = 'https://cloud.r-project.org/') @@ -399,94 +527,96 @@ setup_core_renv_environment() { cat('renv already available globally\n') } " || { - print_error "Failed to install renv" + print_error "Failed to install renv (timeout or error)" exit 1 } print_success "renv is available" - print_step "Setting up core environment with selective package installation" - print_info "This will skip problematic packages and focus on core functionality..." + # Check system library availability + local cairo_available=false + local xml2_available=false + + if check_system_library "cairo" "cairo/cairo.h" "cairo"; then + cairo_available=true + print_info "Cairo system library: Available" + else + print_info "Cairo system library: Not available" + fi + + if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then + xml2_available=true + print_info "XML2 system library: Available" + else + print_info "XML2 system library: Not available" + fi + + print_step "Setting up environment with intelligent package selection" - # Create core restoration script that excludes problematic packages - cat > renv_core_restore.R << 'EOF' -# Core renv restoration script - excludes problematic packages + # Create enhanced restoration script + cat > renv_enhanced_restore.R << EOF +# Enhanced renv restoration script with dependency awareness -cat("=== VIVID VOLCANO CORE INSTALLATION ===\n") +cat("=== VIVID VOLCANO ENHANCED INSTALLATION ===\n") cat("Starting at:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n\n") # Set options options(repos = c(CRAN = "https://cloud.r-project.org/")) -options(timeout = 600) +options(timeout = 300) options(download.file.method = "auto") -# Function to activate renv -activate_renv <- function() { - cat("1. Activating renv environment...\n") - source("renv/activate.R") - cat(" ✓ renv environment activated\n") - cat(" ✓ Primary library path:", .libPaths()[1], "\n") - return(TRUE) -} +# System library availability +CAIRO_AVAILABLE <- ${cairo_available} +XML2_AVAILABLE <- ${xml2_available} + +cat("System library status:\n") +cat(" Cairo available:", CAIRO_AVAILABLE, "\n") +cat(" XML2 available:", XML2_AVAILABLE, "\n\n") + +# Activate renv +cat("1. Activating renv environment...\n") +source("renv/activate.R") +cat(" ✓ renv environment activated\n") -# Function to install core packages only -install_core_packages <- function() { - cat("\n2. Installing core packages (excluding problematic ones)...\n") +# Enhanced package installation +install_enhanced_packages <- function() { + cat("\n2. Installing packages with dependency awareness...\n") library(renv) - # Define core packages for Vivid Volcano functionality + # Core packages (always install) core_packages <- c( - # Shiny core "shiny", "shinyjs", "htmltools", "htmlwidgets", "httpuv", - - # Data manipulation "dplyr", "tidyr", "readr", "data.table", "magrittr", "tibble", "purrr", "stringr", "lubridate", - - # Visualization core "ggplot2", "ggtext", "ggrepel", "scales", "gridExtra", "RColorBrewer", "colourpicker", "viridisLite", - - # Data tables and GT - "DT", "gt", "reactable", - - # Shiny semantic + "DT", "reactable", "shiny.semantic", "semantic.dashboard", "semantic.assets", - - # Essential utilities "jsonlite", "digest", "rlang", "cli", "glue", "lifecycle", "vctrs", "pillar", "fansi", "utf8", - - # File I/O and web "httr", "curl", "mime", "base64enc", "markdown", - - # Alerts and notifications - "shinyalert", - - # Arrow (should work without system deps) - "arrow" + "shinyalert", "arrow" ) - # Optional packages (try but don't fail if they don't work) - optional_packages <- c( - "plotly", # Interactive plots - "Cairo", # Graphics device - "webshot2", # Screenshots - "gt" # Tables - ) + # Conditional packages based on system libraries + conditional_packages <- list() - # Packages to SKIP (known to cause issues) - skip_packages <- c( - "RPostgres", # PostgreSQL - not needed for core functionality - "RSQLite", # SQLite - not needed for core functionality - "V8", # JavaScript - optional - "xml2" # XML - optional for core functionality - ) + if (CAIRO_AVAILABLE) { + conditional_packages[["Cairo"]] <- "Cairo graphics device" + conditional_packages[["webshot2"]] <- "Web screenshots" + } - cat(" Installing", length(core_packages), "core packages...\n") + if (XML2_AVAILABLE) { + conditional_packages[["xml2"]] <- "XML processing" + conditional_packages[["gt"]] <- "Grammar of tables" + } + + # Optional packages (try but don't fail) + optional_packages <- c("plotly") # Install core packages + cat(" Installing", length(core_packages), "core packages...\n") failed_core <- c() for (pkg in core_packages) { cat(" Installing", pkg, "... ") @@ -495,15 +625,32 @@ install_core_packages <- function() { cat("✓\n") TRUE }, error = function(e) { - cat("✗ (", e$message, ")\n") + cat("✗\n") failed_core <<- c(failed_core, pkg) FALSE }) } - cat("\n Attempting optional packages...\n") + # Install conditional packages + if (length(conditional_packages) > 0) { + cat("\n Installing conditional packages...\n") + failed_conditional <- c() + for (pkg in names(conditional_packages)) { + cat(" Installing", pkg, "... ") + result <- tryCatch({ + renv::install(pkg, prompt = FALSE) + cat("✓\n") + TRUE + }, error = function(e) { + cat("✗\n") + failed_conditional <<- c(failed_conditional, pkg) + FALSE + }) + } + } # Try optional packages + cat("\n Installing optional packages...\n") failed_optional <- c() for (pkg in optional_packages) { cat(" Installing", pkg, "... ") @@ -512,408 +659,175 @@ install_core_packages <- function() { cat("✓\n") TRUE }, error = function(e) { - cat("⚠ (optional - ", e$message, ")\n") + cat("⚠\n") failed_optional <<- c(failed_optional, pkg) FALSE }) } - cat("\n Core installation summary:\n") - cat(" ✓ Successful core packages:", length(core_packages) - length(failed_core), "/", length(core_packages), "\n") - cat(" ⚠ Failed core packages:", length(failed_core), "\n") - cat(" ⚠ Failed optional packages:", length(failed_optional), "\n") - cat(" 🚫 Skipped problematic packages:", length(skip_packages), "\n") - - if (length(failed_core) > 0) { - cat(" Failed core packages:", paste(failed_core, collapse = ", "), "\n") + cat("\n Installation summary:\n") + cat(" ✓ Core packages:", length(core_packages) - length(failed_core), "/", length(core_packages), "\n") + if (exists("failed_conditional")) { + cat(" ✓ Conditional packages:", length(conditional_packages) - length(failed_conditional), "/", length(conditional_packages), "\n") } + cat(" ⚠ Failed optional:", length(failed_optional), "\n") - # Return success if most core packages installed success_rate <- (length(core_packages) - length(failed_core)) / length(core_packages) - return(success_rate >= 0.8) # 80% success rate required + return(success_rate >= 0.8) } -# Function to verify installation +# Verification and testing functions verify_installation <- function() { - cat("\n3. Verifying core installation...\n") - - # Essential packages for basic app functionality + cat("\n3. Verifying installation...\n") essential <- c("shiny", "dplyr", "ggplot2", "DT", "shiny.semantic") + missing <- c() - missing_essential <- c() for (pkg in essential) { if (!requireNamespace(pkg, quietly = TRUE)) { - missing_essential <- c(missing_essential, pkg) - cat(" ✗", pkg, "(missing)\n") + missing <- c(missing, pkg) + cat(" ✗", pkg, "\n") } else { cat(" ✓", pkg, "\n") } } - if (length(missing_essential) == 0) { - cat(" ✓ All essential packages verified\n") - return(TRUE) - } else { - cat(" ✗ Missing essential packages:", paste(missing_essential, collapse = ", "), "\n") - return(FALSE) - } + return(length(missing) == 0) } -# Function to test basic app loading test_basic_app <- function() { - cat("\n4. Testing basic app components...\n") - + cat("\n4. Testing app components...\n") tryCatch({ - # Test essential libraries library(shiny, quietly = TRUE) library(dplyr, quietly = TRUE) library(ggplot2, quietly = TRUE) - cat(" ✓ Core libraries load successfully\n") - # Test if app.R can be parsed (not executed) if (file.exists("app.R")) { parsed <- parse("app.R") cat(" ✓ app.R syntax is valid\n") } - return(TRUE) - }, error = function(e) { - cat(" ✗ Error testing app:", e$message, "\n") + cat(" ✗ Error:", e\$message, "\n") return(FALSE) }) } -# Function to create snapshot -create_core_snapshot <- function() { - cat("\n5. Creating environment snapshot...\n") - - tryCatch({ - # Update the lockfile to reflect our core installation - renv::snapshot(prompt = FALSE) - cat(" ✓ Core environment snapshot created\n") - }, error = function(e) { - cat(" ⚠ Could not create snapshot:", e$message, "\n") - cat(" (This is not critical for app functionality)\n") - }) -} - -# Generate summary -generate_summary <- function(install_success, verify_success, test_success) { - cat("\n=== CORE INSTALLATION SUMMARY ===\n") - cat("Completion time:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n") - cat("Working directory:", getwd(), "\n") - cat("R version:", R.version.string, "\n") - cat("renv library:", .libPaths()[1], "\n") +# Main execution +main <- function() { + install_success <- install_enhanced_packages() + verify_success <- verify_installation() + test_success <- test_basic_app() - # Installation status + cat("\n=== INSTALLATION SUMMARY ===\n") if (install_success && verify_success && test_success) { - cat("Installation status: ✓ CORE FUNCTIONALITY READY\n") - status <- "READY" - } else if (install_success && verify_success) { - cat("Installation status: ⚠ CORE PACKAGES INSTALLED (app may work)\n") - status <- "PARTIAL" - } else { - cat("Installation status: ✗ CORE INSTALLATION INCOMPLETE\n") - status <- "INCOMPLETE" - } - - # Check for data files - data_files <- c("GO.parquet2", "www/demo_data.csv") - cat("\nData files status:\n") - for (file in data_files) { - if (file.exists(file)) { - size_mb <- round(file.info(file)$size / 1024 / 1024, 2) - cat(" ✓", file, "(", size_mb, "MB)\n") - } else { - cat(" ✗", file, "(missing)\n") - } - } - - cat("\n=== APPLICATION READY ===\n") - if (status == "READY") { - cat("🎉 Core installation successful!\n") - cat("The application is ready to run in your browser.\n") - } else if (status == "PARTIAL") { - cat("⚠ Partial installation. The app may still work.\n") - cat("Some features may be limited.\n") + cat("Status: ✅ READY TO USE\n") + return("READY") + } else if (verify_success) { + cat("Status: ⚠ CORE FUNCTIONALITY AVAILABLE\n") + return("PARTIAL") } else { - cat("❌ Installation incomplete. Check error messages above.\n") - cat("You may try running the app anyway.\n") + cat("Status: ❌ INSTALLATION INCOMPLETE\n") + return("INCOMPLETE") } - - cat("\nNote: This core installation excludes PostgreSQL and other\n") - cat("problematic packages. The app focuses on volcano plot generation\n") - cat("and GO analysis without database connectivity.\n") - cat("================================\n") - - return(status) -} - -# Main execution -main <- function() { - status <- "INCOMPLETE" - - tryCatch({ - # Step 1: Activate renv - activate_result <- activate_renv() - if (!activate_result) stop("Failed to activate renv") - - # Step 2: Install core packages - install_result <- install_core_packages() - - # Step 3: Verify installation - verify_result <- verify_installation() - - # Step 4: Test basic app functionality - test_result <- test_basic_app() - - # Step 5: Create snapshot - create_core_snapshot() - - # Step 6: Generate summary - status <- generate_summary(install_result, verify_result, test_result) - - if (status %in% c("READY", "PARTIAL")) { - cat("\n🎉 VIVID VOLCANO CORE INSTALLATION COMPLETED! 🎉\n") - return(TRUE) - } else { - cat("\n⚠ INSTALLATION COMPLETED WITH ISSUES ⚠\n") - return(FALSE) - } - - }, error = function(e) { - cat("\n❌ CORE INSTALLATION FAILED ❌\n") - cat("Error:", e$message, "\n") - cat("\nTry:\n") - cat("1. Running the script again\n") - cat("2. Installing R packages manually\n") - cat("3. Checking system dependencies\n") - - return(FALSE) - }) } -# Execute main function result <- main() -if (result) { - cat("✅ Ready to use Vivid Volcano!\n") -} else { - cat("⚠ Installation had issues but may still work\n") -} +cat("Installation result:", result, "\n") +quit(status = if(result %in% c("READY", "PARTIAL")) 0 else 1) EOF - # Execute the core restoration - R --no-restore --no-save < renv_core_restore.R + # Execute the enhanced restoration + R --no-restore --no-save < renv_enhanced_restore.R local exit_code=$? # Clean up - rm -f renv_core_restore.R + rm -f renv_enhanced_restore.R if [[ $exit_code -eq 0 ]]; then - print_success "Core renv environment setup completed" + print_success "R environment setup completed successfully" else - print_warning "Core setup completed with some issues" + print_warning "Setup completed with some limitations" fi } -# Generate simple report -generate_simple_report() { - print_header "GENERATING INSTALLATION REPORT" - - local report_file="vivid_volcano_core_report_$(date +%Y%m%d_%H%M%S).txt" - - cat > "$report_file" << EOF -VIVID VOLCANO CORE INSTALLATION REPORT -====================================== -Date: $(date) -User: $USER -System: $(uname -a) -Working Directory: $(pwd) -Script Version: 3.0 (Core - PostgreSQL-free) - -STRATEGY: -- Focus on core Shiny app functionality -- Exclude problematic packages (RPostgres, RSQLite, V8, etc.) -- Ensure volcano plot generation and GO analysis work -- Skip database connectivity features - -PREREQUISITES: -- Git: $(git --version 2>/dev/null || echo "Not found") -- R Version: $(R --version | head -n1 2>/dev/null || echo "Not found") -- Internet: $(curl -s 1 github.com >/dev/null 2>&1 && echo "Connected" || echo "Not connected") - -REPOSITORY: -- Directory: $(pwd) -- Essential files: $(test -f app.R && echo "app.R ✓" || echo "app.R ✗") $(test -f renv.lock && echo "renv.lock ✓" || echo "renv.lock ✗") - -PACKAGE STRATEGY: -- INCLUDED: shiny, dplyr, ggplot2, DT, ggtext, ggrepel, arrow, gt, etc. -- EXCLUDED: RPostgres, RSQLite, V8, xml2 (problematic) -- OPTIONAL: Cairo, webshot2, plotly (nice to have) - -DATA FILES: -- GO.parquet2: $(test -f GO.parquet2 && echo "Present ($(du -h GO.parquet2 | cut -f1))" || echo "Missing") -- Demo Data: $(test -f www/demo_data.csv && echo "Present" || echo "Missing") - -TO RUN VIVID VOLCANO: -Enhanced launcher (recommended): ./launch_app.sh -R launcher with browser support: R -f launch_app.R -Basic command: R -e "shiny::runApp()" -From RStudio: Open and run app.R - -LIMITATIONS IN THE CORE MASTER VERSION designed to work locally: -- No PostgreSQL database connectivity (Install dependencies manually and clone deployed with telemetry branch of the repository) -- Limited database features - -For support: https://github.com/DatViseR/Vivid-Volcano or datviser@gmail.com -EOF - - print_success "Core installation report saved: $report_file" -} - -# Launch application function +# Launch application with environment detection launch_application() { print_header "LAUNCHING VIVID VOLCANO" - # Check if we're in the right directory - if [[ ! -f "app.R" ]] || [[ ! -f "renv.lock" ]]; then - print_error "Not in Vivid Volcano directory" - print_info "Cannot launch application - essential files missing" + if [[ ! -f "app.R" ]]; then + print_error "app.R not found in current directory" return 1 fi - # Detect operating system for enhanced browser launching - local os_type="unknown" - if [[ "$OSTYPE" == "darwin"* ]]; then - os_type="macos" - print_info "🍎 macOS detected - using enhanced browser launching" - elif [[ "$OSTYPE" == "linux-gnu"* ]]; then - os_type="linux" - print_info "🐧 Linux detected" - elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then - os_type="windows" - print_info "🪟 Windows detected" + # Detect environment for proper configuration + local env=$(detect_environment) + local host="127.0.0.1" + local port="8080" + local launch_browser="TRUE" + + # Container environment configuration + if is_container_environment; then + host="0.0.0.0" + port="3000" + launch_browser="FALSE" + + case $env in + codespaces) + print_info "🌋 Starting Vivid Volcano for GitHub Codespaces..." + print_info "📱 Access through VS Code 'Ports' tab (port 3000)" + ;; + gitpod) + print_info "🌋 Starting Vivid Volcano for Gitpod..." + print_info "📱 Gitpod will automatically open the app in a new tab" + ;; + *) + print_info "🌋 Starting Vivid Volcano for container environment..." + print_info "📱 Access through port 3000" + ;; + esac + print_info "🔗 Make port public to share with colleagues" + else + print_info "🌋 Starting Vivid Volcano..." + print_info "📱 The app will open in your default browser" fi - print_info "🌋 Starting Vivid Volcano (Core Version)..." - print_info "📱 The app will open in your default web browser" - print_info "🛑 To stop the app, press Ctrl+C in this terminal" + print_info "🛑 To stop the app, press Ctrl+C" - # Use enhanced launcher if available, otherwise fallback to basic launcher - if [[ -f "launch_app.R" ]]; then - print_info "🚀 Using enhanced launcher with improved browser support..." + # Launch the application + R --slave --no-restore --no-save -e " + source('renv/activate.R') - R --slave --no-restore --no-save -f launch_app.R - else - print_info "🚀 Using basic launcher..." + essential <- c('shiny', 'dplyr', 'ggplot2', 'DT') + missing <- c() - # Launch the application with enhanced browser launching for macOS - R --slave --no-restore --no-save -e " - # Activate renv - source('renv/activate.R') - - # Check essential packages - essential <- c('shiny', 'dplyr', 'ggplot2', 'DT') - missing <- c() - - for (pkg in essential) { - if (!requireNamespace(pkg, quietly = TRUE)) { - missing <- c(missing, pkg) - } + for (pkg in essential) { + if (!requireNamespace(pkg, quietly = TRUE)) { + missing <- c(missing, pkg) } - - if (length(missing) > 0) { - cat('❌ Missing essential packages:', paste(missing, collapse = ', '), '\n') - cat('Installation may be incomplete\n') - quit(status = 1) - } - - cat('✅ Core environment verified\n') - cat('🚀 Launching Vivid Volcano...\n\n') - - # Load shiny library - library(shiny) - - # Enhanced browser launching for macOS - if (Sys.info()['sysname'] == 'Darwin') { - cat('🍎 macOS detected - using enhanced browser launching...\n') - - # Custom browser launcher for macOS - custom_browser <- function(url) { - cat('📍 App URL:', url, '\n') - success <- FALSE - - # Method 1: Try system open command - tryCatch({ - system(paste('open', url), wait = FALSE) - success <- TRUE - cat('✅ Browser launched via open command\n') - }, error = function(e) { - cat('⚠️ open command failed, trying alternatives...\n') - }) - - # Method 2: Try specific browsers if default failed - if (!success) { - browsers <- c( - '/Applications/Safari.app/Contents/MacOS/Safari', - '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', - '/Applications/Firefox.app/Contents/MacOS/firefox' - ) - - for (browser in browsers) { - if (file.exists(browser)) { - tryCatch({ - system(paste(shQuote(browser), url), wait = FALSE) - success <- TRUE - cat('✅ Browser launched:', basename(browser), '\n') - break - }, error = function(e) { - # Continue to next browser - }) - } - } - } - - # Fallback: provide manual instructions - if (!success) { - cat('⚠️ Automatic browser launching failed\n') - cat('📋 Manual Instructions:\n') - cat(' 1. Open your web browser\n') - cat(' 2. Navigate to:', url, '\n') - cat('🛑 To stop the app, press Ctrl+C\n') - - # Try to copy URL to clipboard - tryCatch({ - system(paste('echo', shQuote(url), '| pbcopy')) - cat('📋 URL copied to clipboard!\n') - }, error = function(e) {}) - } - - cat('🛑 To stop the app, press Ctrl+C in this terminal\n\n') - return(TRUE) - } - - runApp('app.R', launch.browser = custom_browser, host = '127.0.0.1') - } else { - # Standard launching for other platforms - runApp('app.R', launch.browser = TRUE, host = '127.0.0.1') - } - " - fi + } + + if (length(missing) > 0) { + cat('❌ Missing essential packages:', paste(missing, collapse = ', '), '\n') + quit(status = 1) + } + + cat('✅ Environment verified\n') + cat('🚀 Launching Vivid Volcano...\n\n') + + library(shiny) + runApp('app.R', host = '$host', port = $port, launch.browser = $launch_browser) + " local exit_code=$? if [[ $exit_code -eq 0 ]]; then - print_info "👋 Vivid Volcano session ended successfully" + print_info "👋 Vivid Volcano session ended" else print_warning "Application ended with issues" - print_info "💡 Alternative ways to run the app:" - print_info " • Use enhanced launcher: ./launch_app.sh" - print_info " • Use R launcher: R -f launch_app.R" - print_info " • Basic manual run: R -e \"shiny::runApp()\"" + print_info "Manual launch command:" + print_info " R -e \"source('renv/activate.R'); shiny::runApp('app.R', host='$host', port=$port)\"" fi } @@ -921,60 +835,77 @@ launch_application() { main() { local start_time=$(date +%s) - print_header "VIVID VOLCANO CORE INSTALLER" + print_header "VIVID VOLCANO UNIVERSAL INSTALLER v4.2" print_info "Repository: https://github.com/DatViseR/Vivid-Volcano" + print_info "Author: DatViseR" + print_info "Environment: $(detect_environment)" print_info "Started at: $(date)" + print_info "" + print_info "💡 Note: This is a self-hosted alternative." + print_info " For instant access, visit: https://vivid-volcano.com" - # Ask user about system dependencies with individual choice + # Ask user about system dependencies echo - print_info "System dependencies will be presented individually for your selection" - read -p "Proceed with system dependency installation? (Y/n): " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - print_info "Skipping all system dependencies" + if is_container_environment; then + print_info "Container environment detected - will install essential dependencies" + read -p "Proceed with installation? (Y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + print_info "Installation cancelled" + exit 0 + fi else - install_essential_dependencies || { - print_warning "System dependencies installation had issues, but continuing..." - } + print_info "System dependencies will be presented for individual selection" + read -p "Proceed with system dependency installation? (Y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + print_info "Skipping system dependencies" + else + install_enhanced_dependencies || { + print_warning "System dependencies installation had issues, but continuing..." + } + fi fi # Execute installation steps check_prerequisites setup_repository - setup_core_renv_environment - generate_simple_report + setup_enhanced_renv_environment local end_time=$(date +%s) local duration=$((end_time - start_time)) local minutes=$((duration / 60)) local seconds=$((duration % 60)) - print_header "CORE INSTALLATION COMPLETED!" + print_header "INSTALLATION COMPLETED!" print_success "Total time: ${minutes}m ${seconds}s" print_info "Location: $(pwd)" echo - print_header "READY TO USE VIVID VOLCANO!" - - print_step "Features available:" - echo " ✅ Upload CSV/TSV omics data" - echo " ✅ Generate publication-ready volcano plots" - echo " ✅ Perform GO enrichment analysis" - echo " ✅ Interactive and static plot downloads" - echo " ✅ Custom gene labeling and coloring" - echo - print_step "Excluded from core version:" - echo " ❌ PostgreSQL database features" - echo " ❌ Some advanced graphics options" - echo " ❌ Web screenshot features" - echo - - print_success "🎉 Core functionality ready - Vivid Volcano is installed! 🌋" + print_success "🎉 Vivid Volcano is ready! 🌋" + + # Environment-specific usage instructions + if is_container_environment; then + print_info "" + print_info "🌐 CONTAINER USAGE:" + print_info " - App will run on port 3000" + case $(detect_environment) in + codespaces) + print_info " - Access via VS Code 'Ports' tab" + print_info " - Make port public to share with colleagues" + ;; + gitpod) + print_info " - Gitpod will automatically handle port forwarding" + ;; + *) + print_info " - Access via your container's port forwarding" + ;; + esac + fi - # Ask user if they want to run the application now + # Ask if user wants to launch now echo - print_info "The application is ready to run in your browser." - read -p "Would you like to run Vivid Volcano now? (Y/n): " -n 1 -r + read -p "Would you like to launch Vivid Volcano now? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then @@ -982,11 +913,13 @@ main() { launch_application else echo - print_info "You can run Vivid Volcano later by navigating to the Vivid-Volcano directory and running:" - print_info "🚀 Enhanced launcher (recommended): ./launch_app.sh" - print_info "🚀 R launcher with browser support: R -f launch_app.R" - print_info "🚀 Basic command: R -e \"shiny::runApp()\"" - print_info "🚀 Or run the app.R file directly in RStudio" + print_info "To launch later:" + print_info " cd $(pwd)" + if is_container_environment; then + print_info " R -e \"source('renv/activate.R'); shiny::runApp('app.R', host='0.0.0.0', port=3000)\"" + else + print_info " R -e \"source('renv/activate.R'); shiny::runApp()\"" + fi echo print_success "Installation complete! 🌋" fi @@ -999,4 +932,4 @@ trap 'print_error "Installation interrupted"; exit 1' INT TERM # Run main function main "$@" -exit 0 +exit 0 \ No newline at end of file From b6db98765d894ff566dba91d9d1e1ec1b8c53cf5 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 14:46:52 +0200 Subject: [PATCH 2/8] wrong bollean case for R part of the script corrected --- install_vivid_volcano.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index f6133f7..ffc4520 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -534,18 +534,18 @@ setup_enhanced_renv_environment() { print_success "renv is available" # Check system library availability - local cairo_available=false - local xml2_available=false + local cairo_available=FALSE + local xml2_available=FALSE if check_system_library "cairo" "cairo/cairo.h" "cairo"; then - cairo_available=true + cairo_available=TRUE print_info "Cairo system library: Available" else print_info "Cairo system library: Not available" fi if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then - xml2_available=true + xml2_available=TRUE print_info "XML2 system library: Available" else print_info "XML2 system library: Not available" From a94275db47dec8570695aeb9d73be0428723b267 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 15:14:59 +0200 Subject: [PATCH 3/8] additional automatic review for terminal clutter and MacOS dep handling introduced --- install_vivid_volcano.sh | 1237 +++++++++++++++++++++----------------- 1 file changed, 672 insertions(+), 565 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index ffc4520..4d1b833 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -4,48 +4,89 @@ # Vivid Volcano - Universal Installation Script # ==================================================================== # Author: DatViseR -# Date: 2025-07-07 -# Description: Universal installation for local and cloud environments +# Date: 2025-01-08 +# Description: Production-ready universal installer with enhanced macOS dependency handling # Repository: https://github.com/DatViseR/Vivid-Volcano # Works on: macOS, Linux, Codespaces, Gitpod, and other containers # ==================================================================== set -e # Exit on any error -# Colors for output +# Colors and formatting RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' +BOLD='\033[1m' NC='\033[0m' # Logging functions print_header() { - echo -e "\n${PURPLE}=================================${NC}" - echo -e "${PURPLE}$1${NC}" - echo -e "${PURPLE}=================================${NC}\n" + echo -e "\n${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${PURPLE}${BOLD} $1${NC}" + echo -e "${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n" } print_step() { - echo -e "${BLUE}[STEP]${NC} $1" + echo -e "${BLUE}▶${NC} $1" } print_info() { - echo -e "${CYAN}[INFO]${NC} $1" + echo -e "${CYAN}ℹ${NC} $1" } print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + echo -e "${GREEN}✓${NC} $1" } print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + echo -e "${YELLOW}⚠${NC} $1" } print_error() { - echo -e "${RED}[ERROR]${NC} $1" + echo -e "${RED}✗${NC} $1" +} + +# Enhanced progress indicator with spinner +show_progress() { + local message="$1" + local duration="${2:-60}" + local pid=$! + + local spinner='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' + local delay=0.1 + local i=0 + + echo -ne "${CYAN}⏳${NC} $message " + + while kill -0 $pid 2>/dev/null; do + local char="${spinner:$i:1}" + echo -ne "\r${CYAN}⏳${NC} $message ${char}" + sleep $delay + i=$(( (i+1) % ${#spinner} )) + done + + wait $pid + local exit_code=$? + + if [ $exit_code -eq 0 ]; then + echo -e "\r${GREEN}✓${NC} $message - completed successfully" + else + echo -e "\r${RED}✗${NC} $message - failed" + fi + + return $exit_code +} + +# Enhanced command execution with progress +execute_with_progress() { + local command="$1" + local message="$2" + + eval "$command" >/dev/null 2>&1 & + show_progress "$message" } # Utility functions @@ -53,41 +94,27 @@ command_exists() { command -v "$1" >/dev/null 2>&1 } -check_r_version() { - local r_version=$(R --version | head -n1 | grep -o 'R version [0-9]\+\.[0-9]\+\.[0-9]\+' | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+') - local major=$(echo $r_version | cut -d. -f1) - local minor=$(echo $r_version | cut -d. -f2) - - if [[ $major -gt 4 ]] || [[ $major -eq 4 && $minor -ge 4 ]]; then - return 0 - else - return 1 - fi +has_timeout() { + command_exists timeout } detect_environment() { - # Cloud environments if [[ -n "${CODESPACE_NAME:-}" ]] || [[ -n "${GITHUB_CODESPACES:-}" ]]; then echo "codespaces" elif [[ -n "${GITPOD_WORKSPACE_ID:-}" ]]; then echo "gitpod" elif [[ -n "${COLAB_GPU:-}" ]]; then echo "colab" - elif [[ -n "${JUPYTER_SERVER_ROOT:-}" ]]; then - echo "jupyter" - # Local environments elif [[ "$OSTYPE" == "linux-gnu"* ]]; then if command_exists lsb_release; then - echo $(lsb_release -si | tr '[:upper:]' '[:lower:]') + lsb_release -si | tr '[:upper:]' '[:lower:]' elif [[ -f /etc/os-release ]]; then - echo $(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"' | tr '[:upper:]' '[:lower:]') + grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"' | tr '[:upper:]' '[:lower:]' else echo "linux" fi elif [[ "$OSTYPE" == "darwin"* ]]; then echo "macos" - elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then - echo "windows" else echo "unknown" fi @@ -96,11 +123,10 @@ detect_environment() { is_container_environment() { local env=$(detect_environment) case $env in - codespaces|gitpod|colab|jupyter) + codespaces|gitpod|colab) return 0 ;; *) - # Additional container detection if [[ -f /.dockerenv ]] || [[ -f /run/.containerenv ]]; then return 0 fi @@ -109,149 +135,113 @@ is_container_environment() { esac } -# Auto-install missing prerequisites -auto_install_prerequisites() { - print_header "CHECKING AND INSTALLING PREREQUISITES" - - local env=$(detect_environment) - print_info "Detected environment: $env" - - local need_r=false - local need_git=false - - # Check what's missing - if ! command_exists git; then - need_git=true - print_warning "Git is not installed" - fi - +# Enhanced R version check with error handling +check_r_version() { if ! command_exists R; then - need_r=true - print_warning "R is not installed" + return 1 fi - # Auto-install for supported environments - if [[ "$need_git" == true ]] || [[ "$need_r" == true ]]; then - case $env in - codespaces|ubuntu|debian|gitpod) - if command_exists apt-get; then - print_step "Auto-installing prerequisites for $env..." - - # Update package list with proper error handling - print_info "Updating package list..." - sudo apt-get update -qq || { - print_warning "Package list update failed, but continuing..." - } - - local packages_to_install=() - - if [[ "$need_git" == true ]]; then - packages_to_install+=("git") - fi - - if [[ "$need_r" == true ]]; then - packages_to_install+=("r-base" "r-base-dev") - fi - - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - print_info "Installing: ${packages_to_install[*]}" - - # Install with better error handling to prevent freezing - timeout 300 sudo apt-get install -y "${packages_to_install[@]}" || { - print_error "Auto-installation failed or timed out" - print_info "Please install manually:" - [[ "$need_git" == true ]] && print_info " sudo apt-get install git" - [[ "$need_r" == true ]] && print_info " sudo apt-get install r-base r-base-dev" - return 1 - } - - print_success "Prerequisites auto-installed successfully" - fi - fi - ;; - fedora|centos|rhel) - if command_exists dnf; then - print_step "Auto-installing prerequisites for $env..." - local packages_to_install=() - - if [[ "$need_git" == true ]]; then - packages_to_install+=("git") - fi - - if [[ "$need_r" == true ]]; then - packages_to_install+=("R" "R-devel") - fi - - if [[ ${#packages_to_install[@]} -gt 0 ]]; then - sudo dnf install -y "${packages_to_install[@]}" || { - print_warning "Some packages failed to install" - } - fi - fi - ;; - macos) - print_info "macOS detected - please install missing prerequisites manually:" - [[ "$need_git" == true ]] && print_info " Git: Install Xcode Command Line Tools" - [[ "$need_r" == true ]] && print_info " R: Download from https://cran.r-project.org/" - return 1 - ;; - *) - print_warning "Cannot auto-install on $env environment" - print_info "Please install missing prerequisites manually" - return 1 - ;; - esac + local r_version + if has_timeout; then + r_version=$(timeout 10 R --version 2>/dev/null | head -n1 | grep -o 'R version [0-9]\+\.[0-9]\+\.[0-9]\+' | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' 2>/dev/null) || return 1 + else + r_version=$(R --version 2>/dev/null | head -n1 | grep -o 'R version [0-9]\+\.[0-9]\+\.[0-9]\+' | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' 2>/dev/null) || return 1 fi - return 0 + local major minor + major=$(echo "$r_version" | cut -d. -f1) + minor=$(echo "$r_version" | cut -d. -f2) + + if [[ $major -gt 4 ]] || [[ $major -eq 4 && $minor -ge 4 ]]; then + return 0 + else + return 1 + fi } -# Enhanced system library detection +# Enhanced system library detection (especially for macOS Cairo) check_system_library() { local lib_name="$1" local header_file="$2" local pkg_config_name="$3" - # Method 1: Check via pkg-config + # Method 1: pkg-config check if command_exists pkg-config && [[ -n "$pkg_config_name" ]]; then if pkg-config --exists "$pkg_config_name" 2>/dev/null; then return 0 fi fi - # Method 2: Check for header file + # Method 2: Header file search with enhanced macOS paths if [[ -n "$header_file" ]]; then local search_paths=( "/usr/include" "/usr/local/include" - "/opt/homebrew/include" - "/opt/local/include" - "/usr/include/x86_64-linux-gnu" + "/opt/homebrew/include" # Apple Silicon Homebrew + "/usr/local/opt/cairo/include" # Intel Homebrew Cairo + "/opt/homebrew/opt/cairo/include" # Apple Silicon Homebrew Cairo + "/usr/local/opt/libxml2/include" # Intel Homebrew libxml2 + "/opt/homebrew/opt/libxml2/include" # Apple Silicon Homebrew libxml2 + "/opt/local/include" # MacPorts + "/usr/include/x86_64-linux-gnu" # Linux multiarch + "/usr/include/cairo" # Direct Cairo path + "/usr/include/libxml2" # Direct libxml2 path ) for path in "${search_paths[@]}"; do if [[ -f "$path/$header_file" ]]; then return 0 fi + # Also check without subdirectory for some cases + if [[ "$header_file" == *"/"* ]]; then + local base_header + base_header=$(basename "$header_file") + if [[ -f "$path/$base_header" ]]; then + return 0 + fi + fi done fi - # Method 3: OS-specific checks - local env=$(detect_environment) + # Method 3: OS-specific package manager checks + local env + env=$(detect_environment) case $env in macos) - if command_exists brew && brew list "$lib_name" &>/dev/null; then - return 0 + if command_exists brew; then + # Check multiple possible formula names for macOS + local brew_names=("$lib_name") + case $lib_name in + cairo) + brew_names=("cairo" "libcairo") + ;; + xml2) + brew_names=("libxml2" "xml2") + ;; + ssl) + brew_names=("openssl" "openssl@3" "openssl@1.1") + ;; + esac + + for brew_name in "${brew_names[@]}"; do + if brew list "$brew_name" &>/dev/null; then + return 0 + fi + done fi ;; ubuntu|debian|codespaces|gitpod) - if dpkg -l | grep -q "lib${lib_name}.*-dev"; then - return 0 + if command_exists dpkg; then + if dpkg -l 2>/dev/null | grep -q "lib${lib_name}.*-dev"; then + return 0 + fi fi ;; fedora|centos|rhel) - if rpm -qa | grep -q "${lib_name}.*-devel"; then - return 0 + if command_exists rpm; then + if rpm -qa 2>/dev/null | grep -q "${lib_name}.*-devel"; then + return 0 + fi fi ;; esac @@ -259,123 +249,263 @@ check_system_library() { return 1 } -# Enhanced dependency installation with individual choice -install_enhanced_dependencies() { - print_header "SYSTEM DEPENDENCIES INSTALLATION" +# Prerequisites check and auto-installation +check_and_install_prerequisites() { + print_header "PREREQUISITES" - local env=$(detect_environment) + local env + env=$(detect_environment) + local missing_prereqs=false + + # Check and auto-install Git + if ! command_exists git; then + print_warning "Git not found" + case $env in + codespaces|ubuntu|debian|gitpod) + if command_exists apt-get; then + execute_with_progress "sudo apt-get update -qq && sudo apt-get install -y git" "Installing Git" + fi + ;; + macos) + print_info "Install Git via Xcode Command Line Tools: xcode-select --install" + missing_prereqs=true + ;; + esac + else + print_success "Git available" + fi + + # Check and auto-install R + if ! command_exists R; then + print_warning "R not found" + case $env in + codespaces|ubuntu|debian|gitpod) + if command_exists apt-get; then + execute_with_progress "sudo apt-get update -qq && sudo apt-get install -y r-base r-base-dev" "Installing R" + fi + ;; + macos) + print_info "Download R from: https://cran.r-project.org/" + missing_prereqs=true + ;; + esac + else + print_success "R available" + if ! check_r_version; then + print_warning "R version <4.4 detected (4.4+ recommended)" + fi + fi + + # macOS specific checks + if [[ "$env" == "macos" ]]; then + if ! xcode-select -p >/dev/null 2>&1; then + print_warning "Xcode Command Line Tools not installed" + print_info "Run: xcode-select --install" + missing_prereqs=true + fi + + if ! command_exists brew; then + print_warning "Homebrew not found (recommended for dependencies)" + print_info "Install from: https://brew.sh" + fi + fi + + # Final prerequisite check + if [[ "$missing_prereqs" == true ]]; then + print_error "Please install missing prerequisites and rerun the script" + exit 1 + fi + + # Verify we have what we need + if ! command_exists git || ! command_exists R; then + print_error "Required prerequisites still missing after installation attempt" + exit 1 + fi + + # Check disk space + local available_space + available_space=$(df . | tail -1 | awk '{print $4}') + local space_gb=$((available_space / 1024 / 1024)) + + if [[ $space_gb -lt 2 ]]; then + print_warning "Available space: ${space_gb}GB (2GB+ recommended)" + else + print_success "Sufficient disk space: ${space_gb}GB" + fi + + # Check connectivity + if ping -c 1 github.com >/dev/null 2>&1; then + print_success "Internet connectivity confirmed" + else + if is_container_environment; then + print_warning "Limited connectivity (common in containers)" + else + print_error "No GitHub connectivity - check internet connection" + exit 1 + fi + fi + + print_success "All prerequisites satisfied" +} + +# System dependencies installation with proper flow +install_system_dependencies() { + print_header "SYSTEM DEPENDENCIES" + + local env + env=$(detect_environment) print_info "Environment: $env" case $env in ubuntu|debian|codespaces|gitpod) - if command_exists apt-get; then - print_step "Available Ubuntu/Debian dependencies" - sudo apt-get update -qq || print_warning "Package update failed" - - # Core dependencies (always install) - local core_packages=("libssl-dev" "libcurl4-openssl-dev") - print_info "Installing core dependencies: ${core_packages[*]}" - sudo apt-get install -y "${core_packages[@]}" || { - print_error "Failed to install core dependencies" - exit 1 - } - - # Optional dependencies with descriptions - declare -A optional_packages=( - ["libxml2-dev"]="XML library - Optional for XML processing (xml2 package)" - ["libfontconfig1-dev"]="Font configuration - Optional for text rendering" - ["libcairo2-dev"]="Cairo graphics - Optional for high-quality graphics" - ["libharfbuzz-dev"]="Text shaping - Optional for complex text layout" - ["libfribidi-dev"]="Bidirectional text - Optional for right-to-left text" - ["libfreetype6-dev"]="Font rendering - Optional for custom fonts" - ["libpng-dev"]="PNG support - Optional for PNG processing" - ["libjpeg-dev"]="JPEG support - Optional for JPEG processing" - ) - - local selected_packages=() + print_step "Installing system libraries for Ubuntu/Debian" + + # Essential dependencies (no choice) + local essential_packages=("libssl-dev" "libcurl4-openssl-dev") + print_info "Installing essential libraries (required)" + execute_with_progress "sudo apt-get update -qq && sudo apt-get install -y ${essential_packages[*]}" "Installing essential libraries" + + # Optional dependencies with clear explanations + echo + print_step "Optional system libraries (choose which features you want)" + echo + + local optional_deps=( + "libxml2-dev:XML data processing support:Enables xml2 R package for XML/HTML parsing" + "libcairo2-dev:High-quality graphics rendering:Enables Cairo R package for publication-quality plots" + "libfontconfig1-dev:Advanced font support:Better text rendering in plots" + "libharfbuzz-dev:Complex text layout:Support for complex scripts and typography" + "libfribidi-dev:Bidirectional text:Right-to-left text support (Arabic, Hebrew)" + "libfreetype6-dev:Font rendering engine:Enhanced font display" + "libpng-dev:PNG image support:PNG file processing capabilities" + "libjpeg-dev:JPEG image support:JPEG file processing capabilities" + ) + + local selected_packages=() + for pkg_info in "${optional_deps[@]}"; do + local pkg="${pkg_info%%:*}" + local feature="${pkg_info#*:}" + local description="${feature#*:}" + feature="${feature%%:*}" + echo -e "${CYAN}Feature:${NC} $feature" + echo -e "${YELLOW}Package:${NC} $pkg" + echo -e "${BLUE}Description:${NC} $description" + read -p "Install this feature? (Y/n): " -n 1 -r echo - print_info "Optional dependencies (choose individually):" - for pkg in "${!optional_packages[@]}"; do - echo -e "${CYAN}Package:${NC} $pkg" - echo -e "${YELLOW}Description:${NC} ${optional_packages[$pkg]}" - read -p "Install $pkg? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - selected_packages+=("$pkg") - echo -e "${GREEN}✓ Will install $pkg${NC}" - else - echo -e "${YELLOW}⚬ Skipping $pkg${NC}" - fi - echo - done - - if [[ ${#selected_packages[@]} -gt 0 ]]; then - print_info "Installing selected packages: ${selected_packages[*]}" - sudo apt-get install -y "${selected_packages[@]}" || { - print_warning "Some optional packages failed to install" - } + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + selected_packages+=("$pkg") + print_success "Will install $pkg" + else + print_info "Skipping $pkg" fi + echo + done + + if [[ ${#selected_packages[@]} -gt 0 ]]; then + execute_with_progress "sudo apt-get install -y ${selected_packages[*]}" "Installing selected optional libraries" fi ;; - fedora|centos|rhel) - if command_exists dnf; then - local core_packages=("openssl-devel" "libcurl-devel") - print_info "Installing core dependencies: ${core_packages[*]}" - sudo dnf install -y "${core_packages[@]}" + macos) + print_step "Installing system libraries for macOS via Homebrew" + + if ! command_exists brew; then + print_error "Homebrew is required for macOS system dependencies" + print_info "Install Homebrew first: https://brew.sh" + print_info "Then rerun this script" + exit 1 + fi + + # Essential dependencies for macOS + local essential_packages=("openssl" "curl") + print_info "Installing essential libraries" + for pkg in "${essential_packages[@]}"; do + if ! brew list "$pkg" &>/dev/null; then + execute_with_progress "brew install $pkg" "Installing $pkg" + else + print_success "$pkg already installed" + fi + done + + # Optional dependencies with Cairo focus + echo + print_step "Optional Homebrew packages (choose which features you want)" + echo + + local optional_deps=( + "libxml2:XML data processing:Enables xml2 R package for XML/HTML parsing" + "cairo:High-quality graphics rendering:Enables Cairo R package - HIGHLY RECOMMENDED for publication plots" + "harfbuzz:Complex text layout:Advanced typography support" + "fribidi:Bidirectional text:Right-to-left text support" + "freetype:Font rendering engine:Enhanced font display" + "libpng:PNG image support:PNG file processing" + "jpeg:JPEG image support:JPEG file processing" + ) + + local selected_packages=() + for pkg_info in "${optional_deps[@]}"; do + local pkg="${pkg_info%%:*}" + local feature="${pkg_info#*:}" + local description="${feature#*:}" + feature="${feature%%:*}" - declare -A optional_packages=( - ["libxml2-devel"]="XML2 library" - ["fontconfig-devel"]="Font configuration" - ["cairo-devel"]="Cairo graphics" - ["harfbuzz-devel"]="Text shaping" - ["fribidi-devel"]="Bidirectional text" - ["freetype-devel"]="Font rendering" - ["libpng-devel"]="PNG support" - ["libjpeg-turbo-devel"]="JPEG support" - ) + echo -e "${CYAN}Feature:${NC} $feature" + echo -e "${YELLOW}Homebrew package:${NC} $pkg" + echo -e "${BLUE}Description:${NC} $description" - # Similar selection process for optional packages - local selected_packages=() - echo - for pkg in "${!optional_packages[@]}"; do - echo -e "${CYAN}Package:${NC} $pkg - ${optional_packages[$pkg]}" - read -p "Install $pkg? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - selected_packages+=("$pkg") - fi - done + # Special recommendation for Cairo on macOS + if [[ "$pkg" == "cairo" ]]; then + echo -e "${GREEN}⭐ RECOMMENDED:${NC} Cairo fixes common macOS graphics issues" + fi - if [[ ${#selected_packages[@]} -gt 0 ]]; then - sudo dnf install -y "${selected_packages[@]}" + read -p "Install this feature? (Y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + selected_packages+=("$pkg") + print_success "Will install $pkg" + else + print_info "Skipping $pkg" fi - fi + echo + done + + for pkg in "${selected_packages[@]}"; do + if ! brew list "$pkg" &>/dev/null; then + execute_with_progress "brew install $pkg" "Installing $pkg" + else + print_success "$pkg already installed" + fi + done ;; - macos) - if command_exists brew; then - local core_packages=("openssl" "curl") - print_info "Installing core dependencies: ${core_packages[*]}" - brew install "${core_packages[@]}" + fedora|centos|rhel) + print_step "Installing system libraries for Red Hat/Fedora" + + if command_exists dnf; then + local essential_packages=("openssl-devel" "libcurl-devel") + execute_with_progress "sudo dnf install -y ${essential_packages[*]}" "Installing essential libraries" - declare -A optional_packages=( - ["libxml2"]="XML2 library" - ["cairo"]="Cairo graphics" - ["harfbuzz"]="Text shaping" - ["fribidi"]="Bidirectional text" - ["freetype"]="Font rendering" - ["libpng"]="PNG support" - ["jpeg"]="JPEG support" + local optional_deps=( + "libxml2-devel:XML processing" + "cairo-devel:Graphics rendering" + "fontconfig-devel:Font configuration" + "harfbuzz-devel:Text shaping" + "fribidi-devel:Bidirectional text" + "freetype-devel:Font rendering" + "libpng-devel:PNG support" + "libjpeg-turbo-devel:JPEG support" ) - # Similar selection process - local selected_packages=() echo - for pkg in "${!optional_packages[@]}"; do - echo -e "${CYAN}Package:${NC} $pkg - ${optional_packages[$pkg]}" - read -p "Install $pkg? (Y/n): " -n 1 -r + print_step "Optional packages" + local selected_packages=() + + for pkg_desc in "${optional_deps[@]}"; do + local pkg="${pkg_desc%%:*}" + local desc="${pkg_desc##*:}" + echo -e "${CYAN}$pkg${NC} - $desc" + read -p "Install? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then selected_packages+=("$pkg") @@ -383,88 +513,23 @@ install_enhanced_dependencies() { done if [[ ${#selected_packages[@]} -gt 0 ]]; then - brew install "${selected_packages[@]}" + execute_with_progress "sudo dnf install -y ${selected_packages[*]}" "Installing selected packages" fi - else - print_warning "Homebrew not found. Install from: https://brew.sh" fi ;; + + *) + print_warning "Unknown environment - skipping system dependencies" + print_info "You may need to install development libraries manually" + ;; esac -} - -# Prerequisites check with auto-installation -check_prerequisites() { - print_header "CHECKING PREREQUISITES" - - # Attempt auto-installation first - auto_install_prerequisites || { - print_warning "Auto-installation failed or not supported" - print_info "Continuing with manual prerequisite check..." - } - - local missing_deps=() - - # Check Git - if ! command_exists git; then - missing_deps+=("git") - print_error "Git is not installed" - else - print_success "Git found: $(git --version)" - fi - - # Check R with better error handling - if ! command_exists R; then - missing_deps+=("R") - print_error "R is not installed" - else - # Safer R version check - local r_version_output - r_version_output=$(timeout 10 R --version 2>/dev/null | head -n1) || { - print_warning "Could not determine R version (R may be installed but not responding)" - r_version_output="R (version check failed)" - } - print_success "R found: $r_version_output" - - if ! check_r_version 2>/dev/null; then - print_warning "R version should be 4.4+ for optimal compatibility" - fi - fi - - # Check disk space - local available_space=$(df . | tail -1 | awk '{print $4}') - local space_gb=$((available_space / 1024 / 1024)) - - if [[ $space_gb -lt 2 ]]; then - print_warning "Available disk space: ${space_gb}GB (recommend 2GB+)" - else - print_success "Available disk space: ${space_gb}GB" - fi - - # Check internet connectivity - if ping -c 1 github.com >/dev/null 2>&1; then - print_success "Internet connectivity confirmed" - else - # Don't fail in container environments - if is_container_environment; then - print_warning "Limited internet connectivity detected (common in containers)" - else - missing_deps+=("internet") - print_error "No internet connectivity to GitHub" - fi - fi - - if [[ ${#missing_deps[@]} -gt 0 ]]; then - print_error "Missing dependencies: ${missing_deps[*]}" - print_info "Please install missing dependencies and run the script again" - exit 1 - fi - print_success "All prerequisites satisfied" + print_success "System dependencies installation completed" } -# Repository setup (unchanged) +# Repository setup setup_repository() { - print_header "SETTING UP REPOSITORY" + print_header "REPOSITORY SETUP" local repo_url="https://github.com/DatViseR/Vivid-Volcano.git" local repo_dir="Vivid-Volcano" @@ -474,26 +539,14 @@ setup_repository() { cd "$repo_dir" if [[ -d ".git" ]]; then - print_step "Updating existing repository" - git pull origin master || { - print_warning "Could not update repository (continuing with existing version)" - } - else - print_warning "Directory exists but is not a git repository" - print_info "Using existing directory as-is" + execute_with_progress "git pull origin master" "Updating repository" fi else - print_step "Cloning Vivid Volcano repository" - git clone "$repo_url" "$repo_dir" || { - print_error "Failed to clone repository" - exit 1 - } - print_success "Repository cloned successfully" + execute_with_progress "git clone $repo_url $repo_dir" "Cloning Vivid Volcano repository" cd "$repo_dir" fi # Verify essential files - print_step "Verifying repository structure" local essential_files=("app.R" "renv.lock" "renv/activate.R") local missing_files=() @@ -508,124 +561,124 @@ setup_repository() { exit 1 fi - print_success "Repository structure verified" - print_info "Current directory: $(pwd)" + print_success "Repository ready at: $(pwd)" } -# Enhanced renv setup with dependency-aware installation -setup_enhanced_renv_environment() { - print_header "SETTING UP R ENVIRONMENT" +# R environment setup with proper dependency detection +setup_r_environment() { + print_header "R ENVIRONMENT SETUP" + # Install renv print_step "Installing renv package manager" - - # Install renv with timeout to prevent freezing - timeout 120 R --slave --no-restore --no-save -e " - if (!requireNamespace('renv', quietly = TRUE)) { - cat('Installing renv globally...\n') - install.packages('renv', repos = 'https://cloud.r-project.org/') + local renv_cmd='R --slave --no-restore --no-save -e " + if (!requireNamespace(\"renv\", quietly = TRUE)) { + cat(\"Installing renv...\\n\") + install.packages(\"renv\", repos = \"https://cloud.r-project.org/\") } else { - cat('renv already available globally\n') - } - " || { - print_error "Failed to install renv (timeout or error)" - exit 1 - } + cat(\"renv already available\\n\") + }"' - print_success "renv is available" + if has_timeout; then + renv_cmd="timeout 180 $renv_cmd" + fi + + eval "$renv_cmd" & + show_progress "Installing renv package manager" + + # Detect system libraries with R-compatible booleans + print_step "Detecting available system libraries" - # Check system library availability - local cairo_available=FALSE - local xml2_available=FALSE + local cairo_available="FALSE" + local xml2_available="FALSE" if check_system_library "cairo" "cairo/cairo.h" "cairo"; then - cairo_available=TRUE - print_info "Cairo system library: Available" + cairo_available="TRUE" + print_success "Cairo graphics library detected" else - print_info "Cairo system library: Not available" + print_info "Cairo graphics library not found" + if [[ "$(detect_environment)" == "macos" ]]; then + print_info "Install with: brew install cairo" + fi fi if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then - xml2_available=TRUE - print_info "XML2 system library: Available" + xml2_available="TRUE" + print_success "XML2 processing library detected" else - print_info "XML2 system library: Not available" + print_info "XML2 processing library not found" fi - print_step "Setting up environment with intelligent package selection" + # Create R package installation script + print_step "Installing R packages based on available system libraries" - # Create enhanced restoration script - cat > renv_enhanced_restore.R << EOF -# Enhanced renv restoration script with dependency awareness - -cat("=== VIVID VOLCANO ENHANCED INSTALLATION ===\n") -cat("Starting at:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n\n") + cat > install_r_packages.R << 'R_SCRIPT_EOF' +# Vivid Volcano R Package Installation +cat("=== R PACKAGE INSTALLATION ===\n") +cat("Started at:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n\n") -# Set options +# Configuration options(repos = c(CRAN = "https://cloud.r-project.org/")) options(timeout = 300) options(download.file.method = "auto") +options(install.packages.compile.from.source = "never") -# System library availability -CAIRO_AVAILABLE <- ${cairo_available} -XML2_AVAILABLE <- ${xml2_available} +# System library availability (will be replaced by script) +CAIRO_AVAILABLE <- CAIRO_PLACEHOLDER +XML2_AVAILABLE <- XML2_PLACEHOLDER cat("System library status:\n") cat(" Cairo available:", CAIRO_AVAILABLE, "\n") cat(" XML2 available:", XML2_AVAILABLE, "\n\n") -# Activate renv -cat("1. Activating renv environment...\n") +# Activate renv environment +cat("Activating renv environment...\n") source("renv/activate.R") -cat(" ✓ renv environment activated\n") -# Enhanced package installation -install_enhanced_packages <- function() { - cat("\n2. Installing packages with dependency awareness...\n") - +# Package installation function +install_packages <- function() { library(renv) - # Core packages (always install) + # Core packages (always installed - essential for app) core_packages <- c( - "shiny", "shinyjs", "htmltools", "htmlwidgets", "httpuv", - "dplyr", "tidyr", "readr", "data.table", "magrittr", - "tibble", "purrr", "stringr", "lubridate", - "ggplot2", "ggtext", "ggrepel", "scales", "gridExtra", - "RColorBrewer", "colourpicker", "viridisLite", - "DT", "reactable", - "shiny.semantic", "semantic.dashboard", "semantic.assets", - "jsonlite", "digest", "rlang", "cli", "glue", - "lifecycle", "vctrs", "pillar", "fansi", "utf8", - "httr", "curl", "mime", "base64enc", "markdown", - "shinyalert", "arrow" + # Shiny framework + "shiny", "shinyjs", "htmltools", "htmlwidgets", + # Data manipulation + "dplyr", "tidyr", "readr", "stringr", "purrr", "tibble", + # Visualization + "ggplot2", "ggrepel", "ggtext", "scales", + # UI components + "DT", "shiny.semantic", "RColorBrewer", + # Utilities + "jsonlite", "digest", "rlang", "httr", "curl", + "markdown", "shinyalert", "arrow" ) - # Conditional packages based on system libraries + # Conditional packages (only if system libraries available) conditional_packages <- list() - if (CAIRO_AVAILABLE) { - conditional_packages[["Cairo"]] <- "Cairo graphics device" - conditional_packages[["webshot2"]] <- "Web screenshots" + conditional_packages$Cairo <- "High-quality graphics rendering" + conditional_packages$webshot2 <- "Web page screenshots" } - if (XML2_AVAILABLE) { - conditional_packages[["xml2"]] <- "XML processing" - conditional_packages[["gt"]] <- "Grammar of tables" + conditional_packages$xml2 <- "XML/HTML processing" + conditional_packages$gt <- "Advanced table formatting" } - # Optional packages (try but don't fail) + # Optional packages (nice to have) optional_packages <- c("plotly") # Install core packages - cat(" Installing", length(core_packages), "core packages...\n") - failed_core <- c() + cat("Installing", length(core_packages), "core packages...\n") + failed_core <- character(0) + for (pkg in core_packages) { - cat(" Installing", pkg, "... ") + cat(" Installing", pkg, "...") result <- tryCatch({ renv::install(pkg, prompt = FALSE) - cat("✓\n") + cat(" ✓\n") TRUE }, error = function(e) { - cat("✗\n") + cat(" ✗\n") failed_core <<- c(failed_core, pkg) FALSE }) @@ -633,279 +686,335 @@ install_enhanced_packages <- function() { # Install conditional packages if (length(conditional_packages) > 0) { - cat("\n Installing conditional packages...\n") - failed_conditional <- c() + cat("\nInstalling conditional packages (based on system libraries)...\n") + failed_conditional <- character(0) + for (pkg in names(conditional_packages)) { - cat(" Installing", pkg, "... ") + cat(" Installing", pkg, "(", conditional_packages[[pkg]], ") ...") result <- tryCatch({ renv::install(pkg, prompt = FALSE) - cat("✓\n") + cat(" ✓\n") TRUE }, error = function(e) { - cat("✗\n") + cat(" ✗\n") failed_conditional <<- c(failed_conditional, pkg) FALSE }) } } - # Try optional packages - cat("\n Installing optional packages...\n") - failed_optional <- c() + # Install optional packages + cat("\nInstalling optional packages...\n") + failed_optional <- character(0) + for (pkg in optional_packages) { - cat(" Installing", pkg, "... ") - result <- tryCatch({ + cat(" Installing", pkg, "...") + tryCatch({ renv::install(pkg, prompt = FALSE) - cat("✓\n") - TRUE + cat(" ✓\n") }, error = function(e) { - cat("⚠\n") + cat(" ⚠ (optional)\n") failed_optional <<- c(failed_optional, pkg) - FALSE }) } - cat("\n Installation summary:\n") - cat(" ✓ Core packages:", length(core_packages) - length(failed_core), "/", length(core_packages), "\n") + # Installation summary + cat("\n=== INSTALLATION SUMMARY ===\n") + cat("Core packages:", length(core_packages) - length(failed_core), "/", length(core_packages), "\n") if (exists("failed_conditional")) { - cat(" ✓ Conditional packages:", length(conditional_packages) - length(failed_conditional), "/", length(conditional_packages), "\n") + cat("Conditional packages:", length(conditional_packages) - length(failed_conditional), "/", length(conditional_packages), "\n") + } + cat("Optional packages:", length(optional_packages) - length(failed_optional), "/", length(optional_packages), "\n") + + if (length(failed_core) > 0) { + cat("\nFailed core packages:", paste(failed_core, collapse = ", "), "\n") } - cat(" ⚠ Failed optional:", length(failed_optional), "\n") + # Return success if most core packages installed success_rate <- (length(core_packages) - length(failed_core)) / length(core_packages) return(success_rate >= 0.8) } -# Verification and testing functions +# Verification verify_installation <- function() { - cat("\n3. Verifying installation...\n") - essential <- c("shiny", "dplyr", "ggplot2", "DT", "shiny.semantic") - missing <- c() + cat("\n=== VERIFICATION ===\n") + essential <- c("shiny", "dplyr", "ggplot2", "DT") + missing <- character(0) for (pkg in essential) { - if (!requireNamespace(pkg, quietly = TRUE)) { - missing <- c(missing, pkg) - cat(" ✗", pkg, "\n") + if (requireNamespace(pkg, quietly = TRUE)) { + cat("✓", pkg, "\n") } else { - cat(" ✓", pkg, "\n") + cat("✗", pkg, "(missing)\n") + missing <- c(missing, pkg) } } return(length(missing) == 0) } -test_basic_app <- function() { - cat("\n4. Testing app components...\n") +# Test basic app functionality +test_app <- function() { + cat("\n=== APP TEST ===\n") tryCatch({ library(shiny, quietly = TRUE) library(dplyr, quietly = TRUE) library(ggplot2, quietly = TRUE) - cat(" ✓ Core libraries load successfully\n") if (file.exists("app.R")) { - parsed <- parse("app.R") - cat(" ✓ app.R syntax is valid\n") + parse("app.R") + cat("✓ app.R syntax is valid\n") } + + cat("✓ Core components working\n") return(TRUE) + }, error = function(e) { - cat(" ✗ Error:", e\$message, "\n") + cat("✗ Error:", e$message, "\n") return(FALSE) }) } # Main execution -main <- function() { - install_success <- install_enhanced_packages() - verify_success <- verify_installation() - test_success <- test_basic_app() - - cat("\n=== INSTALLATION SUMMARY ===\n") - if (install_success && verify_success && test_success) { - cat("Status: ✅ READY TO USE\n") - return("READY") - } else if (verify_success) { - cat("Status: ⚠ CORE FUNCTIONALITY AVAILABLE\n") - return("PARTIAL") - } else { - cat("Status: ❌ INSTALLATION INCOMPLETE\n") - return("INCOMPLETE") - } -} +install_success <- install_packages() +verify_success <- verify_installation() +test_success <- test_app() -result <- main() -cat("Installation result:", result, "\n") -quit(status = if(result %in% c("READY", "PARTIAL")) 0 else 1) -EOF +if (install_success && verify_success && test_success) { + cat("\n🎉 R environment ready!\n") + quit(status = 0) +} else if (verify_success) { + cat("\n⚠ R environment ready with some limitations\n") + quit(status = 0) +} else { + cat("\n❌ R environment setup incomplete\n") + quit(status = 1) +} +R_SCRIPT_EOF - # Execute the enhanced restoration - R --no-restore --no-save < renv_enhanced_restore.R + # Replace placeholders with actual boolean values + if command_exists sed; then + sed -i.bak "s/CAIRO_PLACEHOLDER/$cairo_available/g" install_r_packages.R + sed -i.bak "s/XML2_PLACEHOLDER/$xml2_available/g" install_r_packages.R + rm -f install_r_packages.R.bak + else + # Fallback for systems without sed + local temp_file + temp_file=$(mktemp) + awk -v cairo="$cairo_available" -v xml2="$xml2_available" ' + {gsub(/CAIRO_PLACEHOLDER/, cairo); gsub(/XML2_PLACEHOLDER/, xml2); print} + ' install_r_packages.R > "$temp_file" + mv "$temp_file" install_r_packages.R + fi - local exit_code=$? + # Execute R package installation + R --no-restore --no-save < install_r_packages.R & + show_progress "Installing R packages (this may take several minutes)" - # Clean up - rm -f renv_enhanced_restore.R + local r_exit_code=$? - if [[ $exit_code -eq 0 ]]; then - print_success "R environment setup completed successfully" + # Cleanup + rm -f install_r_packages.R + + if [[ $r_exit_code -eq 0 ]]; then + print_success "R environment configured successfully" else - print_warning "Setup completed with some limitations" + print_warning "R environment setup completed with some issues" + print_info "Core functionality should still be available" fi } -# Launch application with environment detection +# Application launch with proper instructions launch_application() { - print_header "LAUNCHING VIVID VOLCANO" + print_header "LAUNCH VIVID VOLCANO" if [[ ! -f "app.R" ]]; then print_error "app.R not found in current directory" return 1 fi - # Detect environment for proper configuration - local env=$(detect_environment) + local env + env=$(detect_environment) local host="127.0.0.1" local port="8080" local launch_browser="TRUE" - # Container environment configuration + # Configure for container environments if is_container_environment; then host="0.0.0.0" port="3000" launch_browser="FALSE" + print_step "Configuring for container environment" case $env in codespaces) - print_info "🌋 Starting Vivid Volcano for GitHub Codespaces..." - print_info "📱 Access through VS Code 'Ports' tab (port 3000)" + print_info "🌋 GitHub Codespaces detected" + print_info "📱 Access: VS Code 'Ports' tab → port 3000 → 'Open in Browser'" + print_info "🌐 Share: Right-click port 3000 → 'Port Visibility' → 'Public'" ;; gitpod) - print_info "🌋 Starting Vivid Volcano for Gitpod..." + print_info "🌋 Gitpod detected" print_info "📱 Gitpod will automatically open the app in a new tab" ;; *) - print_info "🌋 Starting Vivid Volcano for container environment..." - print_info "📱 Access through port 3000" + print_info "🌋 Container environment detected" + print_info "📱 Access the app via port 3000" ;; esac - print_info "🔗 Make port public to share with colleagues" else - print_info "🌋 Starting Vivid Volcano..." - print_info "📱 The app will open in your default browser" + print_info "🌋 Local environment detected" + print_info "📱 App will open in your default browser" fi - print_info "🛑 To stop the app, press Ctrl+C" + echo + print_info "🛑 To stop the app: Press Ctrl+C in this terminal" + print_info "💾 Your data stays private - nothing is uploaded to external servers" + echo + # Create launch script + cat > launch_vivid_volcano.R << LAUNCH_EOF +# Vivid Volcano Launch Script +suppressMessages(source('renv/activate.R')) + +# Verify essential packages +essential <- c('shiny', 'dplyr', 'ggplot2', 'DT') +missing <- character(0) + +for (pkg in essential) { + if (!requireNamespace(pkg, quietly = TRUE)) { + missing <- c(missing, pkg) + } +} + +if (length(missing) > 0) { + cat('✗ Missing essential packages:', paste(missing, collapse = ', '), '\n') + cat('Please rerun the installation script.\n') + quit(status = 1) +} + +cat('✓ Environment verified - all essential packages available\n') +cat('🚀 Starting Vivid Volcano...\n\n') + +# Load and launch +suppressMessages(library(shiny)) +runApp('app.R', host = '$host', port = $port, launch.browser = $launch_browser) +LAUNCH_EOF + # Launch the application - R --slave --no-restore --no-save -e " - source('renv/activate.R') - - essential <- c('shiny', 'dplyr', 'ggplot2', 'DT') - missing <- c() - - for (pkg in essential) { - if (!requireNamespace(pkg, quietly = TRUE)) { - missing <- c(missing, pkg) - } - } - - if (length(missing) > 0) { - cat('❌ Missing essential packages:', paste(missing, collapse = ', '), '\n') - quit(status = 1) - } - - cat('✅ Environment verified\n') - cat('🚀 Launching Vivid Volcano...\n\n') - - library(shiny) - runApp('app.R', host = '$host', port = $port, launch.browser = $launch_browser) - " + print_step "Starting Vivid Volcano application" + R --no-restore --no-save < launch_vivid_volcano.R - local exit_code=$? + local app_exit_code=$? + + # Cleanup + rm -f launch_vivid_volcano.R - if [[ $exit_code -eq 0 ]]; then - print_info "👋 Vivid Volcano session ended" + echo + if [[ $app_exit_code -eq 0 ]]; then + print_info "👋 Vivid Volcano session ended normally" else - print_warning "Application ended with issues" - print_info "Manual launch command:" - print_info " R -e \"source('renv/activate.R'); shiny::runApp('app.R', host='$host', port=$port)\"" + print_warning "Application ended unexpectedly" fi + + return $app_exit_code } # Main installation function main() { - local start_time=$(date +%s) - - print_header "VIVID VOLCANO UNIVERSAL INSTALLER v4.2" - print_info "Repository: https://github.com/DatViseR/Vivid-Volcano" - print_info "Author: DatViseR" - print_info "Environment: $(detect_environment)" - print_info "Started at: $(date)" - print_info "" - print_info "💡 Note: This is a self-hosted alternative." - print_info " For instant access, visit: https://vivid-volcano.com" - - # Ask user about system dependencies + local start_time + start_time=$(date +%s) + + # Header + print_header "VIVID VOLCANO INSTALLER v4.4" + echo -e "${CYAN}Repository:${NC} https://github.com/DatViseR/Vivid-Volcano" + echo -e "${CYAN}Author:${NC} DatViseR" + echo -e "${CYAN}Environment:${NC} $(detect_environment)" echo - if is_container_environment; then - print_info "Container environment detected - will install essential dependencies" - read -p "Proceed with installation? (Y/n): " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - print_info "Installation cancelled" - exit 0 - fi + echo -e "${YELLOW}💡 Cloud Alternative:${NC} For instant access, visit ${BLUE}https://vivid-volcano.com${NC}" + echo -e "${CYAN} No installation required, works immediately in any browser${NC}" + echo + + # Installation flow confirmation + echo -e "${BOLD}This installer will:${NC}" + echo " 1. Check and install prerequisites (Git, R)" + echo " 2. Install system libraries (with your choices)" + echo " 3. Download Vivid Volcano repository" + echo " 4. Set up R environment and packages" + echo " 5. Optionally launch the application" + echo + + read -p "Proceed with installation? (Y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + print_info "Installation cancelled" + exit 0 + fi + + # Installation steps + check_and_install_prerequisites + + # System dependencies (optional step) + echo + print_step "System dependencies provide enhanced functionality" + print_info "You can skip this step - the app will work with basic features" + read -p "Install system dependencies with feature selection? (Y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + install_system_dependencies else - print_info "System dependencies will be presented for individual selection" - read -p "Proceed with system dependency installation? (Y/n): " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - print_info "Skipping system dependencies" - else - install_enhanced_dependencies || { - print_warning "System dependencies installation had issues, but continuing..." - } - fi + print_info "Skipping system dependencies - basic features will be available" fi - # Execute installation steps - check_prerequisites setup_repository - setup_enhanced_renv_environment + setup_r_environment - local end_time=$(date +%s) - local duration=$((end_time - start_time)) - local minutes=$((duration / 60)) - local seconds=$((duration % 60)) + # Installation summary + local end_time duration minutes seconds + end_time=$(date +%s) + duration=$((end_time - start_time)) + minutes=$((duration / 60)) + seconds=$((duration % 60)) - print_header "INSTALLATION COMPLETED!" - print_success "Total time: ${minutes}m ${seconds}s" - print_info "Location: $(pwd)" + print_header "INSTALLATION COMPLETE" + print_success "Total installation time: ${minutes}m ${seconds}s" + print_success "Vivid Volcano location: $(pwd)" + # Post-installation instructions + echo + echo -e "${BOLD}🎉 Vivid Volcano is ready to use!${NC}" echo - print_success "🎉 Vivid Volcano is ready! 🌋" + echo -e "${BOLD}Features available:${NC}" + echo " ✓ Upload CSV/TSV omics data" + echo " ✓ Generate publication-ready volcano plots" + echo " ✓ Perform GO enrichment analysis" + echo " ✓ Interactive data filtering and exploration" + echo " ✓ Download high-quality plots and results" + + # Enhanced features based on what was installed + if check_system_library "cairo" "cairo/cairo.h" "cairo"; then + echo " ✓ High-quality Cairo graphics (enhanced plot rendering)" + fi + if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then + echo " ✓ XML data processing capabilities" + fi - # Environment-specific usage instructions + echo + echo -e "${BOLD}Manual launch commands:${NC}" if is_container_environment; then - print_info "" - print_info "🌐 CONTAINER USAGE:" - print_info " - App will run on port 3000" - case $(detect_environment) in - codespaces) - print_info " - Access via VS Code 'Ports' tab" - print_info " - Make port public to share with colleagues" - ;; - gitpod) - print_info " - Gitpod will automatically handle port forwarding" - ;; - *) - print_info " - Access via your container's port forwarding" - ;; - esac + echo -e "${CYAN} cd $(pwd)${NC}" + echo -e "${CYAN} R -e \"source('renv/activate.R'); shiny::runApp('app.R', host='0.0.0.0', port=3000)\"${NC}" + else + echo -e "${CYAN} cd $(pwd)${NC}" + echo -e "${CYAN} R -e \"source('renv/activate.R'); shiny::runApp()\"${NC}" fi - # Ask if user wants to launch now + # Launch option with clear choice + echo + echo -e "${BOLD}Launch Options:${NC}" + echo " [Y] Launch Vivid Volcano now" + echo " [N] Complete installation (launch manually later)" echo - read -p "Would you like to launch Vivid Volcano now? (Y/n): " -n 1 -r + read -p "Your choice (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then @@ -913,23 +1022,21 @@ main() { launch_application else echo - print_info "To launch later:" - print_info " cd $(pwd)" - if is_container_environment; then - print_info " R -e \"source('renv/activate.R'); shiny::runApp('app.R', host='0.0.0.0', port=3000)\"" - else - print_info " R -e \"source('renv/activate.R'); shiny::runApp()\"" - fi - echo - print_success "Installation complete! 🌋" + print_success "🌋 Installation complete!" + print_info "Use the manual launch commands above when ready" fi - - return 0 } # Error handling -trap 'print_error "Installation interrupted"; exit 1' INT TERM +cleanup() { + print_error "Installation interrupted" + # Clean up any temporary files + rm -f install_r_packages.R launch_vivid_volcano.R setup_environment.R 2>/dev/null || true + exit 1 +} + +trap cleanup INT TERM -# Run main function +# Execute main function main "$@" exit 0 \ No newline at end of file From e4fef648f4fb893294995179d69150c7d165bf78 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 15:40:39 +0200 Subject: [PATCH 4/8] Should include all the essential dependencies separated from the optional --- install_vivid_volcano.sh | 412 ++++++++++++++++++++++++++------------- 1 file changed, 281 insertions(+), 131 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index 4d1b833..47b5d21 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -1,11 +1,12 @@ #!/bin/bash # ==================================================================== -# Vivid Volcano - Universal Installation Script +# Vivid Volcano - Universal Installation Script # ==================================================================== # Author: DatViseR # Date: 2025-01-08 -# Description: Production-ready universal installer with enhanced macOS dependency handling +# Description: Production-ready universal installer with corrected package categorization, +# provides information on essential and optional (enhanced functions) dependencies # Repository: https://github.com/DatViseR/Vivid-Volcano # Works on: macOS, Linux, Codespaces, Gitpod, and other containers # ==================================================================== @@ -49,10 +50,9 @@ print_error() { echo -e "${RED}✗${NC} $1" } -# Enhanced progress indicator with spinner +# Enhanced progress indicator show_progress() { local message="$1" - local duration="${2:-60}" local pid=$! local spinner='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' @@ -135,7 +135,7 @@ is_container_environment() { esac } -# Enhanced R version check with error handling +# Enhanced R version check check_r_version() { if ! command_exists R; then return 1 @@ -152,7 +152,7 @@ check_r_version() { major=$(echo "$r_version" | cut -d. -f1) minor=$(echo "$r_version" | cut -d. -f2) - if [[ $major -gt 4 ]] || [[ $major -eq 4 && $minor -ge 4 ]]; then + if [[ $major -gt 4 ]] || [[ $major -eq 4 && $minor -ge 3 ]]; then return 0 else return 1 @@ -292,7 +292,7 @@ check_and_install_prerequisites() { else print_success "R available" if ! check_r_version; then - print_warning "R version <4.4 detected (4.4+ recommended)" + print_warning "R version <4.3 detected (4.3+ recommended for all packages)" fi fi @@ -305,7 +305,7 @@ check_and_install_prerequisites() { fi if ! command_exists brew; then - print_warning "Homebrew not found (recommended for dependencies)" + print_warning "Homebrew not found (recommended for optional dependencies)" print_info "Install from: https://brew.sh" fi fi @@ -362,23 +362,24 @@ install_system_dependencies() { # Essential dependencies (no choice) local essential_packages=("libssl-dev" "libcurl4-openssl-dev") - print_info "Installing essential libraries (required)" + print_info "Installing essential libraries (required for basic functionality)" execute_with_progress "sudo apt-get update -qq && sudo apt-get install -y ${essential_packages[*]}" "Installing essential libraries" # Optional dependencies with clear explanations echo - print_step "Optional system libraries (choose which features you want)" + print_step "Optional system libraries enhance Vivid Volcano features" + print_info "The app works without these, but they enable advanced functionality" echo local optional_deps=( - "libxml2-dev:XML data processing support:Enables xml2 R package for XML/HTML parsing" - "libcairo2-dev:High-quality graphics rendering:Enables Cairo R package for publication-quality plots" - "libfontconfig1-dev:Advanced font support:Better text rendering in plots" - "libharfbuzz-dev:Complex text layout:Support for complex scripts and typography" - "libfribidi-dev:Bidirectional text:Right-to-left text support (Arabic, Hebrew)" - "libfreetype6-dev:Font rendering engine:Enhanced font display" - "libpng-dev:PNG image support:PNG file processing capabilities" - "libjpeg-dev:JPEG image support:JPEG file processing capabilities" + "libxml2-dev:XML data processing:Enables xml2 and gt packages for enhanced tables and data import" + "libcairo2-dev:High-quality graphics:Enables Cairo package for publication-quality plot rendering" + "libfontconfig1-dev:Advanced font support:Better text rendering and font selection in plots" + "libharfbuzz-dev:Complex text layout:Support for advanced typography and text shaping" + "libfribidi-dev:Bidirectional text:Right-to-left text support (Arabic, Hebrew, etc.)" + "libfreetype6-dev:Font rendering engine:Enhanced font display and custom font support" + "libpng-dev:PNG image support:Enhanced PNG file processing and plot export" + "libjpeg-dev:JPEG image support:Enhanced JPEG file processing and plot export" ) local selected_packages=() @@ -390,20 +391,20 @@ install_system_dependencies() { echo -e "${CYAN}Feature:${NC} $feature" echo -e "${YELLOW}Package:${NC} $pkg" - echo -e "${BLUE}Description:${NC} $description" - read -p "Install this feature? (Y/n): " -n 1 -r + echo -e "${BLUE}Benefit:${NC} $description" + read -p "Install this enhancement? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then selected_packages+=("$pkg") print_success "Will install $pkg" else - print_info "Skipping $pkg" + print_info "Skipping $pkg - basic functionality will still work" fi echo done if [[ ${#selected_packages[@]} -gt 0 ]]; then - execute_with_progress "sudo apt-get install -y ${selected_packages[*]}" "Installing selected optional libraries" + execute_with_progress "sudo apt-get install -y ${selected_packages[*]}" "Installing selected enhancements" fi ;; @@ -411,10 +412,10 @@ install_system_dependencies() { print_step "Installing system libraries for macOS via Homebrew" if ! command_exists brew; then - print_error "Homebrew is required for macOS system dependencies" - print_info "Install Homebrew first: https://brew.sh" - print_info "Then rerun this script" - exit 1 + print_warning "Homebrew not found - optional dependencies will be skipped" + print_info "Vivid Volcano will work with basic functionality" + print_info "To install Homebrew later: https://brew.sh" + return 0 fi # Essential dependencies for macOS @@ -428,19 +429,21 @@ install_system_dependencies() { fi done - # Optional dependencies with Cairo focus + # Optional dependencies with Cairo emphasis echo - print_step "Optional Homebrew packages (choose which features you want)" + print_step "Optional Homebrew packages enhance Vivid Volcano features" + print_info "⚠️ macOS Note: These are OPTIONAL - the app works without them" + print_info " Cairo is especially helpful for high-quality plot rendering on macOS" echo local optional_deps=( - "libxml2:XML data processing:Enables xml2 R package for XML/HTML parsing" - "cairo:High-quality graphics rendering:Enables Cairo R package - HIGHLY RECOMMENDED for publication plots" - "harfbuzz:Complex text layout:Advanced typography support" - "fribidi:Bidirectional text:Right-to-left text support" - "freetype:Font rendering engine:Enhanced font display" - "libpng:PNG image support:PNG file processing" - "jpeg:JPEG image support:JPEG file processing" + "libxml2:XML data processing:Enables xml2 and gt packages for enhanced tables" + "cairo:High-quality graphics:Fixes macOS graphics issues and enables publication-quality plots" + "harfbuzz:Advanced typography:Complex text layout and font shaping" + "fribidi:Bidirectional text:Right-to-left language support" + "freetype:Font rendering:Enhanced font display and custom fonts" + "libpng:PNG processing:Enhanced PNG support for plots and data" + "jpeg:JPEG processing:Enhanced JPEG support for plots and data" ) local selected_packages=() @@ -452,20 +455,20 @@ install_system_dependencies() { echo -e "${CYAN}Feature:${NC} $feature" echo -e "${YELLOW}Homebrew package:${NC} $pkg" - echo -e "${BLUE}Description:${NC} $description" + echo -e "${BLUE}Benefit:${NC} $description" # Special recommendation for Cairo on macOS if [[ "$pkg" == "cairo" ]]; then - echo -e "${GREEN}⭐ RECOMMENDED:${NC} Cairo fixes common macOS graphics issues" + echo -e "${GREEN}⭐ RECOMMENDED for macOS:${NC} Solves common graphics rendering issues" fi - read -p "Install this feature? (Y/n): " -n 1 -r + read -p "Install this enhancement? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then selected_packages+=("$pkg") print_success "Will install $pkg" else - print_info "Skipping $pkg" + print_info "Skipping $pkg - app will work without it" fi echo done @@ -498,7 +501,7 @@ install_system_dependencies() { ) echo - print_step "Optional packages" + print_step "Optional packages for enhanced functionality" local selected_packages=() for pkg_desc in "${optional_deps[@]}"; do @@ -520,11 +523,12 @@ install_system_dependencies() { *) print_warning "Unknown environment - skipping system dependencies" - print_info "You may need to install development libraries manually" + print_info "Vivid Volcano will work with basic functionality" + print_info "You may install development libraries manually for enhanced features" ;; esac - print_success "System dependencies installation completed" + print_success "System dependencies configuration completed" } # Repository setup @@ -564,7 +568,7 @@ setup_repository() { print_success "Repository ready at: $(pwd)" } -# R environment setup with proper dependency detection +# R environment setup with complete package list from renv.lock setup_r_environment() { print_header "R ENVIRONMENT SETUP" @@ -595,30 +599,27 @@ setup_r_environment() { cairo_available="TRUE" print_success "Cairo graphics library detected" else - print_info "Cairo graphics library not found" - if [[ "$(detect_environment)" == "macos" ]]; then - print_info "Install with: brew install cairo" - fi + print_info "Cairo graphics library not found (optional)" fi if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then xml2_available="TRUE" print_success "XML2 processing library detected" else - print_info "XML2 processing library not found" + print_info "XML2 processing library not found (optional)" fi - # Create R package installation script - print_step "Installing R packages based on available system libraries" + # Create comprehensive R package installation script based on actual app dependencies + print_step "Installing R packages (this may take several minutes)" cat > install_r_packages.R << 'R_SCRIPT_EOF' -# Vivid Volcano R Package Installation -cat("=== R PACKAGE INSTALLATION ===\n") +# Vivid Volcano Complete R Package Installation +cat("=== COMPREHENSIVE R PACKAGE INSTALLATION ===\n") cat("Started at:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n\n") # Configuration options(repos = c(CRAN = "https://cloud.r-project.org/")) -options(timeout = 300) +options(timeout = 600) options(download.file.method = "auto") options(install.packages.compile.from.source = "never") @@ -634,44 +635,97 @@ cat(" XML2 available:", XML2_AVAILABLE, "\n\n") cat("Activating renv environment...\n") source("renv/activate.R") -# Package installation function +# Complete package installation function based on actual app.R analysis install_packages <- function() { library(renv) - # Core packages (always installed - essential for app) - core_packages <- c( - # Shiny framework - "shiny", "shinyjs", "htmltools", "htmlwidgets", - # Data manipulation - "dplyr", "tidyr", "readr", "stringr", "purrr", "tibble", - # Visualization - "ggplot2", "ggrepel", "ggtext", "scales", - # UI components - "DT", "shiny.semantic", "RColorBrewer", - # Utilities - "jsonlite", "digest", "rlang", "httr", "curl", - "markdown", "shinyalert", "arrow" + # ESSENTIAL CORE PACKAGES (app will NOT work without these) + # Based on library() calls in app.R and core functionality + essential_packages <- c( + # Shiny framework (required) + "shiny", "shinyjs", + + # Data manipulation (required) + "readr", "dplyr", "tidyr", "data.table", "magrittr", + + # Visualization core (required) + "ggplot2", "ggtext", "ggrepel", "scales", "RColorBrewer", + + # Interactive tables (required - core functionality) + "DT", "gt", "plotly", + + # UI framework (required - app uses semantic.dashboard) + "shiny.semantic", "semantic.dashboard", "colourpicker", + + # Data formats (required - app uses arrow for GO data) + "arrow", + + # Essential utilities (required) + "jsonlite", "digest", "rlang", "htmltools", "htmlwidgets", + "httpuv", "R6", + + # Notifications and alerts (required for user feedback) + "shinyalert" + ) + + # ENHANCED PACKAGES (improve functionality but app can work without) + enhanced_packages <- c( + # Additional shiny components + "bslib", "jquerylib", "crosstalk", "reactable", + + # Enhanced data processing + "lubridate", "hms", "bit64", "clipr", "fs", "stringr", "purrr", "tibble", + + # Additional visualization + "gridExtra", "viridisLite", "lattice", "isoband", "farver", "gtable", + + # Graphics and rendering support + "base64enc", "mime", "fontawesome", "markdown", "cachem", "fastmap", + + # System utilities + "lifecycle", "cli", "glue", "fansi", "crayon", "vctrs", "pillar", + + # HTTP and web + "httr", "curl", "askpass", "openssl", + + # Statistical packages + "MASS", "Matrix" ) - # Conditional packages (only if system libraries available) + # CONDITIONAL PACKAGES (only if system libraries available) conditional_packages <- list() + conditional_descriptions <- list() + if (CAIRO_AVAILABLE) { - conditional_packages$Cairo <- "High-quality graphics rendering" - conditional_packages$webshot2 <- "Web page screenshots" + conditional_packages$Cairo <- "Cairo" + conditional_descriptions$Cairo <- "High-quality graphics rendering" + conditional_packages$webshot2 <- "webshot2" + conditional_descriptions$webshot2 <- "Web page screenshots" } + if (XML2_AVAILABLE) { - conditional_packages$xml2 <- "XML/HTML processing" - conditional_packages$gt <- "Advanced table formatting" + conditional_packages$xml2 <- "xml2" + conditional_descriptions$xml2 <- "XML/HTML processing for gt package" + # Note: gt is now in essential as it's used in core functionality } - # Optional packages (nice to have) - optional_packages <- c("plotly") + # SPECIALIZED PACKAGES (may fail on some systems, not critical) + specialized_packages <- c( + "processx", "callr", "later", "promises", "memoise", + "sys", "blob", "DBI", "RSQLite", "RPostgres", + "V8", "chromote", "websocket", "AsioHeaders", + "bigD", "bit", "bitops", "backports", "assertthat", + "checkmate", "cpp11", "Rcpp", "colorspace", "commonmark", + "evaluate", "highr", "knitr", "rmarkdown", "yaml", + "juicyjuice", "labeling", "lazyeval", "pkgconfig", + "withr", "timechange", "generics", "tidyselect" + ) - # Install core packages - cat("Installing", length(core_packages), "core packages...\n") - failed_core <- character(0) + # Install essential packages first (MUST succeed) + cat("Installing", length(essential_packages), "essential packages...\n") + failed_essential <- character(0) - for (pkg in core_packages) { + for (pkg in essential_packages) { cat(" Installing", pkg, "...") result <- tryCatch({ renv::install(pkg, prompt = FALSE) @@ -679,7 +733,24 @@ install_packages <- function() { TRUE }, error = function(e) { cat(" ✗\n") - failed_core <<- c(failed_core, pkg) + failed_essential <<- c(failed_essential, pkg) + FALSE + }) + } + + # Install enhanced packages + cat("\nInstalling", length(enhanced_packages), "enhanced packages...\n") + failed_enhanced <- character(0) + + for (pkg in enhanced_packages) { + cat(" Installing", pkg, "...") + result <- tryCatch({ + renv::install(pkg, prompt = FALSE) + cat(" ✓\n") + TRUE + }, error = function(e) { + cat(" ⚠\n") + failed_enhanced <<- c(failed_enhanced, pkg) FALSE }) } @@ -689,8 +760,10 @@ install_packages <- function() { cat("\nInstalling conditional packages (based on system libraries)...\n") failed_conditional <- character(0) - for (pkg in names(conditional_packages)) { - cat(" Installing", pkg, "(", conditional_packages[[pkg]], ") ...") + for (pkg_key in names(conditional_packages)) { + pkg <- conditional_packages[[pkg_key]] + desc <- conditional_descriptions[[pkg_key]] + cat(" Installing", pkg, "(", desc, ") ...") result <- tryCatch({ renv::install(pkg, prompt = FALSE) cat(" ✓\n") @@ -703,42 +776,55 @@ install_packages <- function() { } } - # Install optional packages - cat("\nInstalling optional packages...\n") - failed_optional <- character(0) + # Install specialized packages (optional) + cat("\nInstalling specialized packages...\n") + failed_specialized <- character(0) - for (pkg in optional_packages) { + for (pkg in specialized_packages) { cat(" Installing", pkg, "...") tryCatch({ renv::install(pkg, prompt = FALSE) cat(" ✓\n") }, error = function(e) { - cat(" ⚠ (optional)\n") - failed_optional <<- c(failed_optional, pkg) + cat(" ⚠\n") + failed_specialized <<- c(failed_specialized, pkg) }) } # Installation summary cat("\n=== INSTALLATION SUMMARY ===\n") - cat("Core packages:", length(core_packages) - length(failed_core), "/", length(core_packages), "\n") + cat("Essential packages:", length(essential_packages) - length(failed_essential), "/", length(essential_packages), "\n") + cat("Enhanced packages:", length(enhanced_packages) - length(failed_enhanced), "/", length(enhanced_packages), "\n") if (exists("failed_conditional")) { cat("Conditional packages:", length(conditional_packages) - length(failed_conditional), "/", length(conditional_packages), "\n") } - cat("Optional packages:", length(optional_packages) - length(failed_optional), "/", length(optional_packages), "\n") + cat("Specialized packages:", length(specialized_packages) - length(failed_specialized), "/", length(specialized_packages), "\n") - if (length(failed_core) > 0) { - cat("\nFailed core packages:", paste(failed_core, collapse = ", "), "\n") + if (length(failed_essential) > 0) { + cat("\n❌ FAILED ESSENTIAL PACKAGES:\n") + for(pkg in failed_essential) { + cat(" -", pkg, "\n") + } + cat("⚠️ These failures WILL prevent the app from starting!\n") } - # Return success if most core packages installed - success_rate <- (length(core_packages) - length(failed_core)) / length(core_packages) - return(success_rate >= 0.8) + # Return success if ALL essential packages installed + success_rate <- (length(essential_packages) - length(failed_essential)) / length(essential_packages) + return(success_rate >= 1.0) # Require ALL essential packages } -# Verification +# Verification with complete package list verify_installation <- function() { cat("\n=== VERIFICATION ===\n") - essential <- c("shiny", "dplyr", "ggplot2", "DT") + + # Must verify ALL essential packages from app.R + essential <- c( + "shiny", "shinyjs", "readr", "dplyr", "ggplot2", "ggtext", + "colourpicker", "ggrepel", "arrow", "DT", "plotly", "gt", + "shiny.semantic", "semantic.dashboard", "gridExtra", "shinyalert", + "tidyr", "data.table", "jsonlite", "htmltools" + ) + missing <- character(0) for (pkg in essential) { @@ -750,27 +836,57 @@ verify_installation <- function() { } } + # Check conditional packages + if (CAIRO_AVAILABLE) { + if (requireNamespace("Cairo", quietly = TRUE)) { + cat("✓ Cairo (conditional)\n") + } else { + cat("⚠ Cairo (conditional - not installed)\n") + } + } + + if (XML2_AVAILABLE) { + if (requireNamespace("xml2", quietly = TRUE)) { + cat("✓ xml2 (conditional)\n") + } else { + cat("⚠ xml2 (conditional - not installed)\n") + } + } + return(length(missing) == 0) } -# Test basic app functionality +# Test app functionality test_app <- function() { - cat("\n=== APP TEST ===\n") + cat("\n=== APP FUNCTIONALITY TEST ===\n") tryCatch({ - library(shiny, quietly = TRUE) - library(dplyr, quietly = TRUE) - library(ggplot2, quietly = TRUE) + # Test ALL core libraries that must load for app to work + suppressMessages({ + library(shiny, quietly = TRUE) + library(shinyjs, quietly = TRUE) + library(dplyr, quietly = TRUE) + library(ggplot2, quietly = TRUE) + library(DT, quietly = TRUE) + library(colourpicker, quietly = TRUE) + library(shiny.semantic, quietly = TRUE) + library(semantic.dashboard, quietly = TRUE) + library(arrow, quietly = TRUE) + library(gt, quietly = TRUE) + library(plotly, quietly = TRUE) + }) + + cat("✓ All essential libraries load successfully\n") if (file.exists("app.R")) { parse("app.R") cat("✓ app.R syntax is valid\n") } - cat("✓ Core components working\n") + cat("✓ All essential components working\n") return(TRUE) }, error = function(e) { - cat("✗ Error:", e$message, "\n") + cat("✗ Error loading essential libraries:", e$message, "\n") return(FALSE) }) } @@ -781,14 +897,22 @@ verify_success <- verify_installation() test_success <- test_app() if (install_success && verify_success && test_success) { - cat("\n🎉 R environment ready!\n") + cat("\n🎉 Complete R environment ready!\n") + cat("All essential packages installed and verified.\n") quit(status = 0) -} else if (verify_success) { - cat("\n⚠ R environment ready with some limitations\n") +} else if (verify_success && test_success) { + cat("\n⚠ R environment ready with some optional features missing\n") + cat("Core functionality available.\n") quit(status = 0) } else { cat("\n❌ R environment setup incomplete\n") - quit(status = 1) + cat("Some essential packages may be missing.\n") + if (test_success) { + cat("However, app syntax test passed - try launching anyway.\n") + quit(status = 0) + } else { + quit(status = 1) + } } R_SCRIPT_EOF @@ -809,7 +933,7 @@ R_SCRIPT_EOF # Execute R package installation R --no-restore --no-save < install_r_packages.R & - show_progress "Installing R packages (this may take several minutes)" + show_progress "Installing complete R package environment" local r_exit_code=$? @@ -820,7 +944,7 @@ R_SCRIPT_EOF print_success "R environment configured successfully" else print_warning "R environment setup completed with some issues" - print_info "Core functionality should still be available" + print_info "Core functionality should be available" fi } @@ -869,15 +993,23 @@ launch_application() { echo print_info "🛑 To stop the app: Press Ctrl+C in this terminal" print_info "💾 Your data stays private - nothing is uploaded to external servers" + print_info "⚡ First startup may take a moment while packages load" echo # Create launch script cat > launch_vivid_volcano.R << LAUNCH_EOF # Vivid Volcano Launch Script +cat("Loading Vivid Volcano environment...\n") suppressMessages(source('renv/activate.R')) -# Verify essential packages -essential <- c('shiny', 'dplyr', 'ggplot2', 'DT') +# Verify ALL essential packages are available (based on app.R analysis) +essential <- c( + 'shiny', 'shinyjs', 'readr', 'dplyr', 'ggplot2', 'ggtext', + 'colourpicker', 'ggrepel', 'arrow', 'DT', 'plotly', 'gt', + 'shiny.semantic', 'semantic.dashboard', 'gridExtra', 'shinyalert', + 'tidyr', 'data.table' +) + missing <- character(0) for (pkg in essential) { @@ -893,15 +1025,19 @@ if (length(missing) > 0) { } cat('✓ Environment verified - all essential packages available\n') -cat('🚀 Starting Vivid Volcano...\n\n') +cat('🚀 Starting Vivid Volcano application...\n') +cat(' First load may take 10-30 seconds...\n\n') + +# Load and launch (suppress startup messages for cleaner output) +suppressPackageStartupMessages({ + library(shiny) +}) -# Load and launch -suppressMessages(library(shiny)) runApp('app.R', host = '$host', port = $port, launch.browser = $launch_browser) LAUNCH_EOF # Launch the application - print_step "Starting Vivid Volcano application" + print_step "Starting Vivid Volcano application..." R --no-restore --no-save < launch_vivid_volcano.R local app_exit_code=$? @@ -925,7 +1061,7 @@ main() { start_time=$(date +%s) # Header - print_header "VIVID VOLCANO INSTALLER v4.4" + print_header "VIVID VOLCANO INSTALLER v4.6" echo -e "${CYAN}Repository:${NC} https://github.com/DatViseR/Vivid-Volcano" echo -e "${CYAN}Author:${NC} DatViseR" echo -e "${CYAN}Environment:${NC} $(detect_environment)" @@ -937,11 +1073,14 @@ main() { # Installation flow confirmation echo -e "${BOLD}This installer will:${NC}" echo " 1. Check and install prerequisites (Git, R)" - echo " 2. Install system libraries (with your choices)" + echo " 2. Install system libraries (optional - your choice)" echo " 3. Download Vivid Volcano repository" - echo " 4. Set up R environment and packages" + echo " 4. Set up complete R environment with all packages" echo " 5. Optionally launch the application" echo + echo -e "${YELLOW}Note:${NC} System dependencies are OPTIONAL for enhanced features" + echo -e "${YELLOW} The app works without them but may have limited functionality${NC}" + echo read -p "Proceed with installation? (Y/n): " -n 1 -r echo @@ -953,11 +1092,14 @@ main() { # Installation steps check_and_install_prerequisites - # System dependencies (optional step) + # System dependencies (optional step with clear explanation) + echo + print_step "System dependencies enable enhanced features" + echo -e "${CYAN}✓ Basic features:${NC} Work without system dependencies" + echo -e "${CYAN}✓ Enhanced features:${NC} High-quality graphics, advanced tables, XML processing" + echo -e "${YELLOW}⚠ macOS users:${NC} Cairo can fix graphics issues but is completely optional" echo - print_step "System dependencies provide enhanced functionality" - print_info "You can skip this step - the app will work with basic features" - read -p "Install system dependencies with feature selection? (Y/n): " -n 1 -r + read -p "Install optional system dependencies for enhanced features? (Y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Nn]$ ]]; then install_system_dependencies @@ -983,19 +1125,27 @@ main() { echo echo -e "${BOLD}🎉 Vivid Volcano is ready to use!${NC}" echo - echo -e "${BOLD}Features available:${NC}" + echo -e "${BOLD}Core features (always available):${NC}" echo " ✓ Upload CSV/TSV omics data" - echo " ✓ Generate publication-ready volcano plots" + echo " ✓ Generate volcano plots" echo " ✓ Perform GO enrichment analysis" - echo " ✓ Interactive data filtering and exploration" - echo " ✓ Download high-quality plots and results" + echo " ✓ Interactive data filtering" + echo " ✓ Download results and plots" + echo " ✓ Interactive plots with plotly" + echo " ✓ Publication-quality tables with gt" # Enhanced features based on what was installed + echo + echo -e "${BOLD}Enhanced features:${NC}" if check_system_library "cairo" "cairo/cairo.h" "cairo"; then - echo " ✓ High-quality Cairo graphics (enhanced plot rendering)" + echo " ✓ High-quality Cairo graphics (publication-ready plots)" + else + echo " ⚬ High-quality graphics (install Cairo for enhanced rendering)" fi if check_system_library "xml2" "libxml/parser.h" "libxml-2.0"; then - echo " ✓ XML data processing capabilities" + echo " ✓ XML data processing and advanced table formatting" + else + echo " ⚬ Advanced table formatting (install libxml2 for full gt package support)" fi echo @@ -1010,8 +1160,8 @@ main() { # Launch option with clear choice echo - echo -e "${BOLD}Launch Options:${NC}" - echo " [Y] Launch Vivid Volcano now" + echo -e "${BOLD}Ready to launch Vivid Volcano?${NC}" + echo " [Y] Start the application now" echo " [N] Complete installation (launch manually later)" echo read -p "Your choice (Y/n): " -n 1 -r @@ -1031,7 +1181,7 @@ main() { cleanup() { print_error "Installation interrupted" # Clean up any temporary files - rm -f install_r_packages.R launch_vivid_volcano.R setup_environment.R 2>/dev/null || true + rm -f install_r_packages.R launch_vivid_volcano.R 2>/dev/null || true exit 1 } From 3ba29467d7fc330a7573b89db1706f84563087f9 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 16:06:34 +0200 Subject: [PATCH 5/8] The app now handles missing optional cairo and webshot dependencies --- app.R | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/app.R b/app.R index dfa00d2..b848314 100644 --- a/app.R +++ b/app.R @@ -15,12 +15,47 @@ library(ggrepel) library(arrow) library(DT) library(plotly) -library(Cairo) + +# Cairo Graphics Library - Conditional Loading +# Cairo provides high-quality graphics rendering and is especially beneficial for: +# - Publication-quality plot output with better anti-aliasing +# - Consistent cross-platform graphics rendering +# - Enhanced PDF/PNG export capabilities +# - Better font rendering and Unicode support +# +# macOS Installation Issues: +# Cairo can be problematic on macOS due to: +# - Complex system dependencies (X11, fontconfig, freetype) +# - Conflicts between Homebrew Intel/ARM installations +# - Xcode Command Line Tools version mismatches +# - Different Cairo versions in system vs. Homebrew paths +# +# The app functions without Cairo using R's default graphics devices, +# but users may experience slightly lower quality plot rendering. + +if (requireNamespace("Cairo", quietly = TRUE)) { + library(Cairo) + message("✓ Cairo graphics library loaded - enhanced plot rendering available") +} else { + message("ℹ Cairo not available - using default graphics (install Cairo for enhanced rendering)") +} + library(gt) library(shiny.semantic) library(semantic.dashboard) library(gridExtra) -library(webshot2) + +# WebShot2 - Conditional Loading +# WebShot2 enables web page screenshots and may depend on Cairo availability +# Falls back gracefully if not available + +if (requireNamespace("webshot2", quietly = TRUE)) { + library(webshot2) + message("✓ WebShot2 loaded - screenshot capabilities available") +} else { + message("ℹ WebShot2 not available - some export features may be limited") +} + library(shinyalert) library(tidyr) library(data.table) From b6bfb3d38898afbf34cd2ef32167d64c99fb73e2 Mon Sep 17 00:00:00 2001 From: DatViseR Date: Mon, 7 Jul 2025 17:10:34 +0200 Subject: [PATCH 6/8] Enhanced info on R packadge life-time installation --- install_vivid_volcano.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index 47b5d21..0de7d07 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -372,7 +372,7 @@ install_system_dependencies() { echo local optional_deps=( - "libxml2-dev:XML data processing:Enables xml2 and gt packages for enhanced tables and data import" + "libxml2-dev:XML data processing:Enables xml2 package for XML/HTML parsing and web scraping (gt tables should work without this - install only if you have issueus with GT tables display in the app" "libcairo2-dev:High-quality graphics:Enables Cairo package for publication-quality plot rendering" "libfontconfig1-dev:Advanced font support:Better text rendering and font selection in plots" "libharfbuzz-dev:Complex text layout:Support for advanced typography and text shaping" @@ -932,10 +932,11 @@ R_SCRIPT_EOF fi # Execute R package installation - R --no-restore --no-save < install_r_packages.R & - show_progress "Installing complete R package environment" - - local r_exit_code=$? + print_step "Installing R packages with detailed progress..." +echo +R --no-restore --no-save < install_r_packages.R + +local r_exit_code=$? # Cleanup rm -f install_r_packages.R From 37e7e6ea2d51dc9262a924e13dd835883d5f5d8d Mon Sep 17 00:00:00 2001 From: DatViseR Date: Tue, 8 Jul 2025 09:56:12 +0200 Subject: [PATCH 7/8] Included some important info for the installation script users --- install_vivid_volcano.sh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/install_vivid_volcano.sh b/install_vivid_volcano.sh index 0de7d07..a4dcd49 100644 --- a/install_vivid_volcano.sh +++ b/install_vivid_volcano.sh @@ -437,7 +437,7 @@ install_system_dependencies() { echo local optional_deps=( - "libxml2:XML data processing:Enables xml2 and gt packages for enhanced tables" + "libxml2:XML data processing::Enables xml2 package for XML/HTML parsing and web scraping (gt tables should work without this - install only if you have issueus with GT tables display in the app" "cairo:High-quality graphics:Fixes macOS graphics issues and enables publication-quality plots" "harfbuzz:Advanced typography:Complex text layout and font shaping" "fribidi:Bidirectional text:Right-to-left language support" @@ -524,7 +524,7 @@ install_system_dependencies() { *) print_warning "Unknown environment - skipping system dependencies" print_info "Vivid Volcano will work with basic functionality" - print_info "You may install development libraries manually for enhanced features" + print_info "You may install system libraries manually for enhanced features" ;; esac @@ -1062,13 +1062,23 @@ main() { start_time=$(date +%s) # Header - print_header "VIVID VOLCANO INSTALLER v4.6" + print_header "VIVID VOLCANO UNIVERSAL INSTALLER" echo -e "${CYAN}Repository:${NC} https://github.com/DatViseR/Vivid-Volcano" echo -e "${CYAN}Author:${NC} DatViseR" echo -e "${CYAN}Environment:${NC} $(detect_environment)" echo - echo -e "${YELLOW}💡 Cloud Alternative:${NC} For instant access, visit ${BLUE}https://vivid-volcano.com${NC}" - echo -e "${CYAN} No installation required, works immediately in any browser${NC}" + echo -e "${YELLOW}💡Public Cloud availible:${NC} For instant access, visit ${BLUE}https://datviser-vivid-volcano.share.connect.posit.cloud/${NC}" + echo -e "${CYAN} Availible via web; Data privacy: When you use this cloud-based application, your data is processed securely within your own session. What it means : + + Your uploaded data is not stored permanently, and it is not accessible to other users. + + Each session is isolated, meaning your data is only available during your active session and is automatically cleared when the session ends (including temporal logs). + + Vivid Volcano does not collect, store, or share any uploaded files or analysis results. It collects non-sensitive telemetry data - number of sessions, analyses performed, time of sessions etc.... + + For your safety, I recommend not uploading highly sensitive data (ex. not blinded patients data) , as the app is hosted on a public server without authentication. For sensitive data you can + use this installer to install the app localy or in your own cloud container. + ${NC}" echo # Installation flow confirmation From 5c3503bb1caa2dcbf0b453acdcf12cea5cfbcf2c Mon Sep 17 00:00:00 2001 From: DatViseR Date: Tue, 8 Jul 2025 10:09:30 +0200 Subject: [PATCH 8/8] added information on Webshot2 dependency - optional for disabled gt tables pdf export functionality --- app.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app.R b/app.R index b848314..20657c9 100644 --- a/app.R +++ b/app.R @@ -49,6 +49,11 @@ library(gridExtra) # WebShot2 enables web page screenshots and may depend on Cairo availability # Falls back gracefully if not available +# This version of the app exports GT tables as HTML files and does not depend on +# webshot2. PDF export depends on webshot2 which is not working in the posit connect cloud - that is why +# export was changed to HTML export. You can enable +#pdf export by modifying the downloadHandler() code for gt tables before installation in your private server + if (requireNamespace("webshot2", quietly = TRUE)) { library(webshot2) message("✓ WebShot2 loaded - screenshot capabilities available")