mirror of
				https://github.com/community-scripts/ProxmoxVE.git
				synced 2025-11-04 10:22:50 +00:00 
			
		
		
		
	Update tools.func (#4507)
This commit is contained in:
		
							
								
								
									
										337
									
								
								misc/tools.func
									
									
									
									
									
								
							
							
						
						
									
										337
									
								
								misc/tools.func
									
									
									
									
									
								
							@@ -1,4 +1,17 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs Node.js and optional global modules.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Installs specified Node.js version using NodeSource APT repo
 | 
				
			||||||
 | 
					#   - Optionally installs or updates global npm modules
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   NODE_VERSION   - Node.js version to install (default: 22)
 | 
				
			||||||
 | 
					#   NODE_MODULE    - Comma-separated list of global modules (e.g. "yarn,@vue/cli@5.0.0")
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_node_and_modules() {
 | 
					install_node_and_modules() {
 | 
				
			||||||
  local NODE_VERSION="${NODE_VERSION:-22}"
 | 
					  local NODE_VERSION="${NODE_VERSION:-22}"
 | 
				
			||||||
  local NODE_MODULE="${NODE_MODULE:-}"
 | 
					  local NODE_MODULE="${NODE_MODULE:-}"
 | 
				
			||||||
@@ -99,6 +112,19 @@ install_node_and_modules() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or upgrades PostgreSQL and performs data migration.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Detects existing PostgreSQL version
 | 
				
			||||||
 | 
					#   - Dumps all databases before upgrade
 | 
				
			||||||
 | 
					#   - Adds PGDG repo and installs specified version
 | 
				
			||||||
 | 
					#   - Restores dumped data post-upgrade
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   PG_VERSION     - Major PostgreSQL version (e.g. 15, 16) (default: 16)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_postgresql() {
 | 
					install_postgresql() {
 | 
				
			||||||
  local PG_VERSION="${PG_VERSION:-16}"
 | 
					  local PG_VERSION="${PG_VERSION:-16}"
 | 
				
			||||||
  local CURRENT_PG_VERSION=""
 | 
					  local CURRENT_PG_VERSION=""
 | 
				
			||||||
@@ -115,7 +141,7 @@ install_postgresql() {
 | 
				
			|||||||
    msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION"
 | 
					    msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION"
 | 
				
			||||||
    NEED_PG_INSTALL=true
 | 
					    NEED_PG_INSTALL=true
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    msg_info "PostgreSQL not installed, proceeding with fresh install of $PG_VERSION"
 | 
					    msg_info "Setup PostgreSQL $PG_VERSION"
 | 
				
			||||||
    NEED_PG_INSTALL=true
 | 
					    NEED_PG_INSTALL=true
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -123,10 +149,10 @@ install_postgresql() {
 | 
				
			|||||||
    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
					    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
				
			||||||
      msg_info "Dumping all PostgreSQL data from version $CURRENT_PG_VERSION"
 | 
					      msg_info "Dumping all PostgreSQL data from version $CURRENT_PG_VERSION"
 | 
				
			||||||
      su - postgres -c "pg_dumpall > /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql"
 | 
					      su - postgres -c "pg_dumpall > /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql"
 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    msg_info "Stopping PostgreSQL service"
 | 
					      msg_info "Stopping PostgreSQL service"
 | 
				
			||||||
    systemctl stop postgresql || true
 | 
					      systemctl stop postgresql
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    msg_info "Removing pgdg repo and old GPG key"
 | 
					    msg_info "Removing pgdg repo and old GPG key"
 | 
				
			||||||
    rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg
 | 
					    rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg
 | 
				
			||||||
@@ -149,7 +175,7 @@ install_postgresql() {
 | 
				
			|||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $STD msg_info "Starting PostgreSQL $PG_VERSION"
 | 
					    $STD msg_info "Starting PostgreSQL $PG_VERSION"
 | 
				
			||||||
    systemctl enable --now postgresql
 | 
					    systemctl enable -q --now postgresql
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
					    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
				
			||||||
      $STD msg_info "Restoring dumped data"
 | 
					      $STD msg_info "Restoring dumped data"
 | 
				
			||||||
@@ -160,6 +186,18 @@ install_postgresql() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or updates MariaDB from official repo.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Detects current MariaDB version and replaces it if necessary
 | 
				
			||||||
 | 
					#   - Preserves existing database data
 | 
				
			||||||
 | 
					#   - Dynamically determines latest GA version if "latest" is given
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   MARIADB_VERSION - MariaDB version to install (e.g. 10.11, latest) (default: latest)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_mariadb() {
 | 
					install_mariadb() {
 | 
				
			||||||
  local MARIADB_VERSION="${MARIADB_VERSION:-latest}"
 | 
					  local MARIADB_VERSION="${MARIADB_VERSION:-latest}"
 | 
				
			||||||
  local DISTRO_CODENAME
 | 
					  local DISTRO_CODENAME
 | 
				
			||||||
@@ -167,13 +205,18 @@ install_mariadb() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  # grab dynamic latest LTS version
 | 
					  # grab dynamic latest LTS version
 | 
				
			||||||
  if [[ "$MARIADB_VERSION" == "latest" ]]; then
 | 
					  if [[ "$MARIADB_VERSION" == "latest" ]]; then
 | 
				
			||||||
    msg_info "Resolving latest MariaDB version"
 | 
					    $STD msg_info "Resolving latest GA MariaDB version"
 | 
				
			||||||
    MARIADB_VERSION=$(curl -fsSL https://mariadb.org | grep -oP 'MariaDB \K10\.[0-9]+' | head -n1)
 | 
					    MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ |
 | 
				
			||||||
 | 
					      grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' |
 | 
				
			||||||
 | 
					      grep -vE 'rc/|rolling/' |
 | 
				
			||||||
 | 
					      sed 's|/||' |
 | 
				
			||||||
 | 
					      sort -Vr |
 | 
				
			||||||
 | 
					      head -n1)
 | 
				
			||||||
    if [[ -z "$MARIADB_VERSION" ]]; then
 | 
					    if [[ -z "$MARIADB_VERSION" ]]; then
 | 
				
			||||||
      msg_error "Could not determine latest MariaDB version"
 | 
					      msg_error "Could not determine latest GA MariaDB version"
 | 
				
			||||||
      return 1
 | 
					      return 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    msg_ok "Latest MariaDB version is $MARIADB_VERSION"
 | 
					    $STD msg_ok "Latest GA MariaDB version is $MARIADB_VERSION"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  local CURRENT_VERSION=""
 | 
					  local CURRENT_VERSION=""
 | 
				
			||||||
@@ -182,23 +225,23 @@ install_mariadb() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if [[ "$CURRENT_VERSION" == "$MARIADB_VERSION" ]]; then
 | 
					  if [[ "$CURRENT_VERSION" == "$MARIADB_VERSION" ]]; then
 | 
				
			||||||
    msg_info "MariaDB $MARIADB_VERSION already installed, checking for upgrade"
 | 
					    $STD msg_info "MariaDB $MARIADB_VERSION, upgrading"
 | 
				
			||||||
    $STD apt-get update
 | 
					    $STD apt-get update
 | 
				
			||||||
    $STD apt-get install --only-upgrade -y mariadb-server mariadb-client
 | 
					    $STD apt-get install --only-upgrade -y mariadb-server mariadb-client
 | 
				
			||||||
    msg_ok "MariaDB $MARIADB_VERSION upgraded if applicable"
 | 
					    $STD msg_ok "MariaDB upgraded to $MARIADB_VERSION"
 | 
				
			||||||
    return 0
 | 
					    return 0
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if [[ -n "$CURRENT_VERSION" ]]; then
 | 
					  if [[ -n "$CURRENT_VERSION" ]]; then
 | 
				
			||||||
    msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)"
 | 
					    $STD msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)"
 | 
				
			||||||
    $STD systemctl stop mariadb >/dev/null 2>&1 || true
 | 
					    $STD systemctl stop mariadb >/dev/null 2>&1 || true
 | 
				
			||||||
    $STD apt-get purge -y 'mariadb*' || true
 | 
					    $STD apt-get purge -y 'mariadb*' || true
 | 
				
			||||||
    rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
					    rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    msg_info "Installing MariaDB $MARIADB_VERSION"
 | 
					    msg_info "Setup MariaDB $MARIADB_VERSION"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  msg_info "Setting up MariaDB Repository"
 | 
					  $STD msg_info "Setting up MariaDB Repository"
 | 
				
			||||||
  curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" |
 | 
					  curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" |
 | 
				
			||||||
    gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
					    gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -208,9 +251,21 @@ install_mariadb() {
 | 
				
			|||||||
  $STD apt-get update
 | 
					  $STD apt-get update
 | 
				
			||||||
  $STD apt-get install -y mariadb-server mariadb-client
 | 
					  $STD apt-get install -y mariadb-server mariadb-client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  msg_ok "Installed MariaDB $MARIADB_VERSION"
 | 
					  msg_ok "Setup MariaDB $MARIADB_VERSION"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or upgrades MySQL and configures APT repo.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Detects existing MySQL installation
 | 
				
			||||||
 | 
					#   - Purges conflicting packages before installation
 | 
				
			||||||
 | 
					#   - Supports clean upgrade
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   MYSQL_VERSION  - MySQL version to install (e.g. 5.7, 8.0) (default: 8.0)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_mysql() {
 | 
					install_mysql() {
 | 
				
			||||||
  local MYSQL_VERSION="${MYSQL_VERSION:-8.0}"
 | 
					  local MYSQL_VERSION="${MYSQL_VERSION:-8.0}"
 | 
				
			||||||
  local CURRENT_VERSION=""
 | 
					  local CURRENT_VERSION=""
 | 
				
			||||||
@@ -248,11 +303,33 @@ install_mysql() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs PHP with selected modules and configures Apache/FPM support.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Adds Sury PHP repo if needed
 | 
				
			||||||
 | 
					#   - Installs default and user-defined modules
 | 
				
			||||||
 | 
					#   - Patches php.ini for CLI, Apache, and FPM as needed
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   PHP_VERSION                - PHP version to install (default: 8.4)
 | 
				
			||||||
 | 
					#   PHP_MODULE                 - Additional comma-separated modules
 | 
				
			||||||
 | 
					#   PHP_APACHE                 - Set YES to enable PHP with Apache
 | 
				
			||||||
 | 
					#   PHP_FPM                    - Set YES to enable PHP-FPM
 | 
				
			||||||
 | 
					#   PHP_MEMORY_LIMIT           - (default: 512M)
 | 
				
			||||||
 | 
					#   PHP_UPLOAD_MAX_FILESIZE    - (default: 128M)
 | 
				
			||||||
 | 
					#   PHP_POST_MAX_SIZE          - (default: 128M)
 | 
				
			||||||
 | 
					#   PHP_MAX_EXECUTION_TIME     - (default: 300)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_php() {
 | 
					install_php() {
 | 
				
			||||||
  local PHP_VERSION="${PHP_VERSION:-8.4}"
 | 
					  local PHP_VERSION="${PHP_VERSION:-8.4}"
 | 
				
			||||||
  local PHP_MODULE="${PHP_MODULE:-}"
 | 
					  local PHP_MODULE="${PHP_MODULE:-}"
 | 
				
			||||||
  local PHP_APACHE="${PHP_APACHE:-NO}"
 | 
					  local PHP_APACHE="${PHP_APACHE:-NO}"
 | 
				
			||||||
  local PHP_FPM="${PHP_FPM:-NO}"
 | 
					  local PHP_FPM="${PHP_FPM:-NO}"
 | 
				
			||||||
 | 
					  local DISTRO_CODENAME
 | 
				
			||||||
 | 
					  DISTRO_CODENAME=$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  local DEFAULT_MODULES="bcmath,cli,curl,gd,intl,mbstring,opcache,readline,xml,zip"
 | 
					  local DEFAULT_MODULES="bcmath,cli,curl,gd,intl,mbstring,opcache,readline,xml,zip"
 | 
				
			||||||
  local COMBINED_MODULES
 | 
					  local COMBINED_MODULES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -279,11 +356,11 @@ install_php() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if [[ "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
 | 
					  if [[ "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
 | 
				
			||||||
    $STD echo "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION"
 | 
					    $STD msg_info "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION"
 | 
				
			||||||
    if [[ ! -f /etc/apt/sources.list.d/php.list ]]; then
 | 
					    if [[ ! -f /etc/apt/sources.list.d/php.list ]]; then
 | 
				
			||||||
      $STD curl -fsSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
 | 
					      $STD curl -fsSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
 | 
				
			||||||
      $STD dpkg -i /tmp/debsuryorg-archive-keyring.deb
 | 
					      $STD dpkg -i /tmp/debsuryorg-archive-keyring.deb
 | 
				
			||||||
      echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" \
 | 
					      echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ ${DISTRO_CODENAME} main" \
 | 
				
			||||||
        >/etc/apt/sources.list.d/php.list
 | 
					        >/etc/apt/sources.list.d/php.list
 | 
				
			||||||
      $STD apt-get update
 | 
					      $STD apt-get update
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
@@ -329,16 +406,24 @@ install_php() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  for ini in "${PHP_INI_PATHS[@]}"; do
 | 
					  for ini in "${PHP_INI_PATHS[@]}"; do
 | 
				
			||||||
    if [[ -f "$ini" ]]; then
 | 
					    if [[ -f "$ini" ]]; then
 | 
				
			||||||
      msg_info "Patching $ini"
 | 
					      $STD msg_info "Patching $ini"
 | 
				
			||||||
      sed -i "s|^memory_limit = .*|memory_limit = ${PHP_MEMORY_LIMIT}|" "$ini"
 | 
					      sed -i "s|^memory_limit = .*|memory_limit = ${PHP_MEMORY_LIMIT}|" "$ini"
 | 
				
			||||||
      sed -i "s|^upload_max_filesize = .*|upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}|" "$ini"
 | 
					      sed -i "s|^upload_max_filesize = .*|upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}|" "$ini"
 | 
				
			||||||
      sed -i "s|^post_max_size = .*|post_max_size = ${PHP_POST_MAX_SIZE}|" "$ini"
 | 
					      sed -i "s|^post_max_size = .*|post_max_size = ${PHP_POST_MAX_SIZE}|" "$ini"
 | 
				
			||||||
      sed -i "s|^max_execution_time = .*|max_execution_time = ${PHP_MAX_EXECUTION_TIME}|" "$ini"
 | 
					      sed -i "s|^max_execution_time = .*|max_execution_time = ${PHP_MAX_EXECUTION_TIME}|" "$ini"
 | 
				
			||||||
      msg_ok "Patched $ini"
 | 
					      $STD msg_ok "Patched $ini"
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
  done
 | 
					  done
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or updates Composer globally.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Downloads latest version from getcomposer.org
 | 
				
			||||||
 | 
					#   - Installs to /usr/local/bin/composer
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_composer() {
 | 
					install_composer() {
 | 
				
			||||||
  local COMPOSER_BIN="/usr/local/bin/composer"
 | 
					  local COMPOSER_BIN="/usr/local/bin/composer"
 | 
				
			||||||
  export COMPOSER_ALLOW_SUPERUSER=1
 | 
					  export COMPOSER_ALLOW_SUPERUSER=1
 | 
				
			||||||
@@ -347,14 +432,14 @@ install_composer() {
 | 
				
			|||||||
  if [[ -x "$COMPOSER_BIN" ]]; then
 | 
					  if [[ -x "$COMPOSER_BIN" ]]; then
 | 
				
			||||||
    local CURRENT_VERSION
 | 
					    local CURRENT_VERSION
 | 
				
			||||||
    CURRENT_VERSION=$("$COMPOSER_BIN" --version | awk '{print $3}')
 | 
					    CURRENT_VERSION=$("$COMPOSER_BIN" --version | awk '{print $3}')
 | 
				
			||||||
    msg_info "Composer $CURRENT_VERSION found, updating to latest"
 | 
					    $STD msg_info "Composer $CURRENT_VERSION found, updating to latest"
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    msg_info "Composer not found, installing latest version"
 | 
					    msg_info "Setup Composer"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Download and install latest composer
 | 
					  # Download and install latest composer
 | 
				
			||||||
  curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php
 | 
					  curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php
 | 
				
			||||||
  php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer >/dev/null 2>&1
 | 
					  php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer &>/dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if [[ $? -ne 0 ]]; then
 | 
					  if [[ $? -ne 0 ]]; then
 | 
				
			||||||
    msg_error "Failed to install Composer"
 | 
					    msg_error "Failed to install Composer"
 | 
				
			||||||
@@ -365,6 +450,17 @@ install_composer() {
 | 
				
			|||||||
  msg_ok "Installed Composer $($COMPOSER_BIN --version | awk '{print $3}')"
 | 
					  msg_ok "Installed Composer $($COMPOSER_BIN --version | awk '{print $3}')"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs Go (Golang) from official tarball.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Determines system architecture
 | 
				
			||||||
 | 
					#   - Downloads latest version if GO_VERSION not set
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   GO_VERSION     - Version to install (e.g. 1.22.2 or latest)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_go() {
 | 
					install_go() {
 | 
				
			||||||
  local ARCH
 | 
					  local ARCH
 | 
				
			||||||
  case "$(uname -m)" in
 | 
					  case "$(uname -m)" in
 | 
				
			||||||
@@ -420,6 +516,17 @@ install_go() {
 | 
				
			|||||||
  msg_ok "Installed Go $GO_VERSION"
 | 
					  msg_ok "Installed Go $GO_VERSION"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs Temurin JDK via Adoptium APT repository.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Removes previous JDK if version mismatch
 | 
				
			||||||
 | 
					#   - Installs or upgrades to specified JAVA_VERSION
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   JAVA_VERSION   - Temurin JDK version to install (e.g. 17, 21)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_java() {
 | 
					install_java() {
 | 
				
			||||||
  local JAVA_VERSION="${JAVA_VERSION:-21}"
 | 
					  local JAVA_VERSION="${JAVA_VERSION:-21}"
 | 
				
			||||||
  local DISTRO_CODENAME
 | 
					  local DISTRO_CODENAME
 | 
				
			||||||
@@ -460,6 +567,17 @@ install_java() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or updates MongoDB to specified major version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Preserves data across installations
 | 
				
			||||||
 | 
					#   - Adds official MongoDB repo
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   MONGO_VERSION  - MongoDB major version to install (e.g. 7.0, 8.0)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_mongodb() {
 | 
					install_mongodb() {
 | 
				
			||||||
  local MONGO_VERSION="${MONGO_VERSION:-8.0}"
 | 
					  local MONGO_VERSION="${MONGO_VERSION:-8.0}"
 | 
				
			||||||
  local DISTRO_CODENAME
 | 
					  local DISTRO_CODENAME
 | 
				
			||||||
@@ -508,6 +626,19 @@ install_mongodb() {
 | 
				
			|||||||
  msg_ok "MongoDB $MONGO_VERSION installed and started"
 | 
					  msg_ok "MongoDB $MONGO_VERSION installed and started"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Downloads and deploys latest GitHub release tarball.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Fetches latest release from GitHub API
 | 
				
			||||||
 | 
					#   - Detects matching asset by architecture
 | 
				
			||||||
 | 
					#   - Extracts to /opt/<app> and saves version
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   APP            - Override default application name (optional)
 | 
				
			||||||
 | 
					#   GITHUB_TOKEN   - (optional) GitHub token for private rate limits
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fetch_and_deploy_gh_release() {
 | 
					fetch_and_deploy_gh_release() {
 | 
				
			||||||
  local repo="$1"
 | 
					  local repo="$1"
 | 
				
			||||||
  local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')}
 | 
					  local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')}
 | 
				
			||||||
@@ -518,13 +649,11 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
  local api_response tag http_code
 | 
					  local api_response tag http_code
 | 
				
			||||||
  local current_version=""
 | 
					  local current_version=""
 | 
				
			||||||
  local curl_timeout="--connect-timeout 10 --max-time 30"
 | 
					  local curl_timeout="--connect-timeout 10 --max-time 30"
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Check if the app directory exists and if there's a version file
 | 
					  # Check if the app directory exists and if there's a version file
 | 
				
			||||||
  if [[ -f "/opt/${app}_version.txt" ]]; then
 | 
					  if [[ -f "/opt/${app}_version.txt" ]]; then
 | 
				
			||||||
    current_version=$(cat "/opt/${app}_version.txt")
 | 
					    current_version=$(cat "/opt/${app}_version.txt")
 | 
				
			||||||
    $STD msg_info "Current version: $current_version"
 | 
					    $STD msg_info "Current version: $current_version"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # ensure that jq is installed
 | 
					  # ensure that jq is installed
 | 
				
			||||||
  if ! command -v jq &>/dev/null; then
 | 
					  if ! command -v jq &>/dev/null; then
 | 
				
			||||||
    $STD msg_info "Installing jq..."
 | 
					    $STD msg_info "Installing jq..."
 | 
				
			||||||
@@ -534,58 +663,45 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
      return 1
 | 
					      return 1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  [[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN")
 | 
					  [[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN")
 | 
				
			||||||
 | 
					 | 
				
			||||||
  until [[ $attempt -ge $max_attempts ]]; do
 | 
					  until [[ $attempt -ge $max_attempts ]]; do
 | 
				
			||||||
    ((attempt++)) || true
 | 
					    ((attempt++)) || true
 | 
				
			||||||
    $STD msg_info "[$attempt/$max_attempts] Fetching GitHub release for $repo...\n"
 | 
					    $STD msg_info "[$attempt/$max_attempts] Fetching GitHub release for $repo...\n"
 | 
				
			||||||
 | 
					 | 
				
			||||||
    api_response=$(curl $curl_timeout -fsSL -w "%{http_code}" -o /tmp/gh_resp.json "${header[@]}" "$api_url")
 | 
					    api_response=$(curl $curl_timeout -fsSL -w "%{http_code}" -o /tmp/gh_resp.json "${header[@]}" "$api_url")
 | 
				
			||||||
    http_code="${api_response:(-3)}"
 | 
					    http_code="${api_response:(-3)}"
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if [[ "$http_code" == "404" ]]; then
 | 
					    if [[ "$http_code" == "404" ]]; then
 | 
				
			||||||
      msg_error "Repository $repo has no Release candidate (404)"
 | 
					      msg_error "Repository $repo has no Release candidate (404)"
 | 
				
			||||||
      return 1
 | 
					      return 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if [[ "$http_code" != "200" ]]; then
 | 
					    if [[ "$http_code" != "200" ]]; then
 | 
				
			||||||
      $STD msg_info "Request failed with HTTP $http_code, retrying...\n"
 | 
					      $STD msg_info "Request failed with HTTP $http_code, retrying...\n"
 | 
				
			||||||
      sleep $((attempt * 2))
 | 
					      sleep $((attempt * 2))
 | 
				
			||||||
      continue
 | 
					      continue
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
    api_response=$(</tmp/gh_resp.json)
 | 
					    api_response=$(</tmp/gh_resp.json)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if echo "$api_response" | grep -q "API rate limit exceeded"; then
 | 
					    if echo "$api_response" | grep -q "API rate limit exceeded"; then
 | 
				
			||||||
      msg_error "GitHub API rate limit exceeded."
 | 
					      msg_error "GitHub API rate limit exceeded."
 | 
				
			||||||
      return 1
 | 
					      return 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if echo "$api_response" | jq -e '.message == "Not Found"' &>/dev/null; then
 | 
					    if echo "$api_response" | jq -e '.message == "Not Found"' &>/dev/null; then
 | 
				
			||||||
      msg_error "Repository not found: $repo"
 | 
					      msg_error "Repository not found: $repo"
 | 
				
			||||||
      return 1
 | 
					      return 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
    tag=$(echo "$api_response" | jq -r '.tag_name // .name // empty')
 | 
					    tag=$(echo "$api_response" | jq -r '.tag_name // .name // empty')
 | 
				
			||||||
    [[ "$tag" =~ ^v[0-9] ]] && tag="${tag:1}"
 | 
					    [[ "$tag" =~ ^v[0-9] ]] && tag="${tag:1}"
 | 
				
			||||||
    version="${tag#v}"
 | 
					    version="${tag#v}"
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if [[ -z "$tag" ]]; then
 | 
					    if [[ -z "$tag" ]]; then
 | 
				
			||||||
      $STD msg_info "Empty tag received, retrying...\n"
 | 
					      $STD msg_info "Empty tag received, retrying...\n"
 | 
				
			||||||
      sleep $((attempt * 2))
 | 
					      sleep $((attempt * 2))
 | 
				
			||||||
      continue
 | 
					      continue
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
    $STD msg_ok "Found release: $tag for $repo"
 | 
					    $STD msg_ok "Found release: $tag for $repo"
 | 
				
			||||||
    break
 | 
					    break
 | 
				
			||||||
  done
 | 
					  done
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if [[ -z "$tag" ]]; then
 | 
					  if [[ -z "$tag" ]]; then
 | 
				
			||||||
    msg_error "Failed to fetch release for $repo after $max_attempts attempts."
 | 
					    msg_error "Failed to fetch release for $repo after $max_attempts attempts."
 | 
				
			||||||
    exit 1
 | 
					    exit 1
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Version comparison (if we already have this version, skip)
 | 
					  # Version comparison (if we already have this version, skip)
 | 
				
			||||||
  if [[ "$current_version" == "$tag" ]]; then
 | 
					  if [[ "$current_version" == "$tag" ]]; then
 | 
				
			||||||
    $STD msg_info "Already running the latest version ($tag). Skipping update."
 | 
					    $STD msg_info "Already running the latest version ($tag). Skipping update."
 | 
				
			||||||
@@ -595,11 +711,9 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
  local base_url="https://github.com/$repo/releases/download/v$tag"
 | 
					  local base_url="https://github.com/$repo/releases/download/v$tag"
 | 
				
			||||||
  local tmpdir
 | 
					  local tmpdir
 | 
				
			||||||
  tmpdir=$(mktemp -d) || return 1
 | 
					  tmpdir=$(mktemp -d) || return 1
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Extract list of assets from the Release API
 | 
					  # Extract list of assets from the Release API
 | 
				
			||||||
  local assets urls
 | 
					  local assets urls
 | 
				
			||||||
  assets=$(echo "$api_response" | jq -r '.assets[].browser_download_url') || true
 | 
					  assets=$(echo "$api_response" | jq -r '.assets[].browser_download_url') || true
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Detect current architecture
 | 
					  # Detect current architecture
 | 
				
			||||||
  local arch
 | 
					  local arch
 | 
				
			||||||
  if command -v dpkg &>/dev/null; then
 | 
					  if command -v dpkg &>/dev/null; then
 | 
				
			||||||
@@ -616,7 +730,6 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
    arch="unknown"
 | 
					    arch="unknown"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
  $STD msg_info "Detected system architecture: $arch"
 | 
					  $STD msg_info "Detected system architecture: $arch"
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Try to find a matching asset for our architecture
 | 
					  # Try to find a matching asset for our architecture
 | 
				
			||||||
  local url=""
 | 
					  local url=""
 | 
				
			||||||
  for u in $assets; do
 | 
					  for u in $assets; do
 | 
				
			||||||
@@ -626,7 +739,6 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
      break
 | 
					      break
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
  done
 | 
					  done
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Fallback to other architectures if our specific one isn't found
 | 
					  # Fallback to other architectures if our specific one isn't found
 | 
				
			||||||
  if [[ -z "$url" ]]; then
 | 
					  if [[ -z "$url" ]]; then
 | 
				
			||||||
    for u in $assets; do
 | 
					    for u in $assets; do
 | 
				
			||||||
@@ -637,7 +749,6 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
      fi
 | 
					      fi
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Fallback to any tar.gz
 | 
					  # Fallback to any tar.gz
 | 
				
			||||||
  if [[ -z "$url" ]]; then
 | 
					  if [[ -z "$url" ]]; then
 | 
				
			||||||
    for u in $assets; do
 | 
					    for u in $assets; do
 | 
				
			||||||
@@ -648,7 +759,6 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
      fi
 | 
					      fi
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Final fallback to GitHub source tarball
 | 
					  # Final fallback to GitHub source tarball
 | 
				
			||||||
  if [[ -z "$url" ]]; then
 | 
					  if [[ -z "$url" ]]; then
 | 
				
			||||||
    # Use tarball_url directly from API response instead of constructing our own URL
 | 
					    # Use tarball_url directly from API response instead of constructing our own URL
 | 
				
			||||||
@@ -661,18 +771,14 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    $STD msg_info "Using GitHub source tarball: $url"
 | 
					    $STD msg_info "Using GitHub source tarball: $url"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  local filename="${url##*/}"
 | 
					  local filename="${url##*/}"
 | 
				
			||||||
  $STD msg_info "Downloading $url"
 | 
					  $STD msg_info "Downloading $url"
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ! curl $curl_timeout -fsSL -o "$tmpdir/$filename" "$url"; then
 | 
					  if ! curl $curl_timeout -fsSL -o "$tmpdir/$filename" "$url"; then
 | 
				
			||||||
    msg_error "Failed to download release asset from $url"
 | 
					    msg_error "Failed to download release asset from $url"
 | 
				
			||||||
    rm -rf "$tmpdir"
 | 
					    rm -rf "$tmpdir"
 | 
				
			||||||
    return 1
 | 
					    return 1
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  mkdir -p "/opt/$app"
 | 
					  mkdir -p "/opt/$app"
 | 
				
			||||||
 | 
					 | 
				
			||||||
  tar -xzf "$tmpdir/$filename" -C "$tmpdir"
 | 
					  tar -xzf "$tmpdir/$filename" -C "$tmpdir"
 | 
				
			||||||
  local content_root
 | 
					  local content_root
 | 
				
			||||||
  content_root=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d)
 | 
					  content_root=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d)
 | 
				
			||||||
@@ -681,12 +787,19 @@ fetch_and_deploy_gh_release() {
 | 
				
			|||||||
  else
 | 
					  else
 | 
				
			||||||
    cp -r "$tmpdir"/* "/opt/$app/"
 | 
					    cp -r "$tmpdir"/* "/opt/$app/"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
  echo "$version" >"/opt/${app}_version.txt"
 | 
					  echo "$version" >"/opt/${app}_version.txt"
 | 
				
			||||||
  $STD msg_ok "Deployed $app v$version to /opt/$app"
 | 
					  $STD msg_ok "Deployed $app v$version to /opt/$app"
 | 
				
			||||||
  rm -rf "$tmpdir"
 | 
					  rm -rf "$tmpdir"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs a local IP updater script using networkd-dispatcher.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Stores current IP in /run/local-ip.env
 | 
				
			||||||
 | 
					#   - Automatically runs on network changes
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setup_local_ip_helper() {
 | 
					setup_local_ip_helper() {
 | 
				
			||||||
  local BASE_DIR="/usr/local/community-scripts/ip-management"
 | 
					  local BASE_DIR="/usr/local/community-scripts/ip-management"
 | 
				
			||||||
  local SCRIPT_PATH="$BASE_DIR/update_local_ip.sh"
 | 
					  local SCRIPT_PATH="$BASE_DIR/update_local_ip.sh"
 | 
				
			||||||
@@ -759,6 +872,13 @@ EOF
 | 
				
			|||||||
  $STD msg_ok "LOCAL_IP helper installed using networkd-dispatcher"
 | 
					  $STD msg_ok "LOCAL_IP helper installed using networkd-dispatcher"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Loads LOCAL_IP from persistent store or detects if missing.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Loads from /run/local-ip.env or performs runtime lookup
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import_local_ip() {
 | 
					import_local_ip() {
 | 
				
			||||||
  local IP_FILE="/run/local-ip.env"
 | 
					  local IP_FILE="/run/local-ip.env"
 | 
				
			||||||
  if [[ -f "$IP_FILE" ]]; then
 | 
					  if [[ -f "$IP_FILE" ]]; then
 | 
				
			||||||
@@ -796,6 +916,14 @@ import_local_ip() {
 | 
				
			|||||||
  export LOCAL_IP
 | 
					  export LOCAL_IP
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Downloads file with optional progress indicator using pv.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Arguments:
 | 
				
			||||||
 | 
					#   $1 - URL
 | 
				
			||||||
 | 
					#   $2 - Destination path
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function download_with_progress() {
 | 
					function download_with_progress() {
 | 
				
			||||||
  local url="$1"
 | 
					  local url="$1"
 | 
				
			||||||
  local output="$2"
 | 
					  local output="$2"
 | 
				
			||||||
@@ -824,6 +952,14 @@ function download_with_progress() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or upgrades uv (Python package manager) from GitHub releases.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Downloads architecture-specific tarball
 | 
				
			||||||
 | 
					#   - Places binary in /usr/local/bin
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function setup_uv() {
 | 
					function setup_uv() {
 | 
				
			||||||
  $STD msg_info "Checking uv installation..."
 | 
					  $STD msg_info "Checking uv installation..."
 | 
				
			||||||
  UV_BIN="/usr/local/bin/uv"
 | 
					  UV_BIN="/usr/local/bin/uv"
 | 
				
			||||||
@@ -877,6 +1013,13 @@ function setup_uv() {
 | 
				
			|||||||
  msg_ok "uv installed/updated to $LATEST_VERSION"
 | 
					  msg_ok "uv installed/updated to $LATEST_VERSION"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Ensures /usr/local/bin is permanently in system PATH.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Adds to /etc/profile.d if not present
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function ensure_usr_local_bin_persist() {
 | 
					function ensure_usr_local_bin_persist() {
 | 
				
			||||||
  local PROFILE_FILE="/etc/profile.d/custom_path.sh"
 | 
					  local PROFILE_FILE="/etc/profile.d/custom_path.sh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -886,6 +1029,14 @@ function ensure_usr_local_bin_persist() {
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs or updates Ghostscript (gs) from source.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Fetches latest release
 | 
				
			||||||
 | 
					#   - Builds and installs system-wide
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function setup_gs() {
 | 
					function setup_gs() {
 | 
				
			||||||
  msg_info "Setup Ghostscript"
 | 
					  msg_info "Setup Ghostscript"
 | 
				
			||||||
  mkdir -p /tmp
 | 
					  mkdir -p /tmp
 | 
				
			||||||
@@ -939,3 +1090,93 @@ function setup_gs() {
 | 
				
			|||||||
    msg_error "Ghostscript installation failed"
 | 
					    msg_error "Ghostscript installation failed"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					# Installs rbenv and ruby-build, installs Ruby and optionally Rails.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Description:
 | 
				
			||||||
 | 
					#   - Downloads rbenv and ruby-build from GitHub
 | 
				
			||||||
 | 
					#   - Compiles and installs target Ruby version
 | 
				
			||||||
 | 
					#   - Optionally installs Rails via gem
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables:
 | 
				
			||||||
 | 
					#   RUBY_VERSION         - Ruby version to install (default: 3.4.4)
 | 
				
			||||||
 | 
					#   RUBY_INSTALL_RAILS   - true/false to install Rails (default: true)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_rbenv_stack() {
 | 
				
			||||||
 | 
					  local RUBY_VERSION="${RUBY_VERSION:-3.4.4}"
 | 
				
			||||||
 | 
					  local RUBY_INSTALL_RAILS="${RUBY_INSTALL_RAILS:-true}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  local RBENV_DIR="$HOME/.rbenv"
 | 
				
			||||||
 | 
					  local RBENV_BIN="$RBENV_DIR/bin/rbenv"
 | 
				
			||||||
 | 
					  local PROFILE_FILE="$HOME/.profile"
 | 
				
			||||||
 | 
					  local TMP_DIR
 | 
				
			||||||
 | 
					  TMP_DIR=$(mktemp -d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $STD msg_info "Installing rbenv + ruby-build + Ruby $RUBY_VERSION"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Fetch latest rbenv release tag from GitHub (e.g. v1.3.2 → 1.3.2)
 | 
				
			||||||
 | 
					  local RBENV_RELEASE
 | 
				
			||||||
 | 
					  RBENV_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/rbenv/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//')
 | 
				
			||||||
 | 
					  if [[ -z "$RBENV_RELEASE" ]]; then
 | 
				
			||||||
 | 
					    msg_error "Failed to fetch latest rbenv version"
 | 
				
			||||||
 | 
					    rm -rf "$TMP_DIR"
 | 
				
			||||||
 | 
					    return 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Download and extract rbenv release
 | 
				
			||||||
 | 
					  curl -fsSL "https://github.com/rbenv/rbenv/archive/refs/tags/v${RBENV_RELEASE}.tar.gz" -o "$TMP_DIR/rbenv.tar.gz"
 | 
				
			||||||
 | 
					  tar -xzf "$TMP_DIR/rbenv.tar.gz" -C "$TMP_DIR"
 | 
				
			||||||
 | 
					  mkdir -p "$RBENV_DIR"
 | 
				
			||||||
 | 
					  cp -r "$TMP_DIR/rbenv-${RBENV_RELEASE}/." "$RBENV_DIR/"
 | 
				
			||||||
 | 
					  cd "$RBENV_DIR" && src/configure && make -C src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Fetch latest ruby-build plugin release tag (e.g. v20250507 → 20250507)
 | 
				
			||||||
 | 
					  local RUBY_BUILD_RELEASE
 | 
				
			||||||
 | 
					  RUBY_BUILD_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/ruby-build/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//')
 | 
				
			||||||
 | 
					  if [[ -z "$RUBY_BUILD_RELEASE" ]]; then
 | 
				
			||||||
 | 
					    msg_error "Failed to fetch latest ruby-build version"
 | 
				
			||||||
 | 
					    rm -rf "$TMP_DIR"
 | 
				
			||||||
 | 
					    return 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Download and install ruby-build plugin
 | 
				
			||||||
 | 
					  curl -fsSL "https://github.com/rbenv/ruby-build/archive/refs/tags/v${RUBY_BUILD_RELEASE}.tar.gz" -o "$TMP_DIR/ruby-build.tar.gz"
 | 
				
			||||||
 | 
					  tar -xzf "$TMP_DIR/ruby-build.tar.gz" -C "$TMP_DIR"
 | 
				
			||||||
 | 
					  mkdir -p "$RBENV_DIR/plugins/ruby-build"
 | 
				
			||||||
 | 
					  cp -r "$TMP_DIR/ruby-build-${RUBY_BUILD_RELEASE}/." "$RBENV_DIR/plugins/ruby-build/"
 | 
				
			||||||
 | 
					  echo "$RUBY_BUILD_RELEASE" >"$RBENV_DIR/plugins/ruby-build/RUBY_BUILD_version.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Persist rbenv init to user's profile
 | 
				
			||||||
 | 
					  if ! grep -q 'rbenv init' "$PROFILE_FILE"; then
 | 
				
			||||||
 | 
					    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >>"$PROFILE_FILE"
 | 
				
			||||||
 | 
					    echo 'eval "$(rbenv init -)"' >>"$PROFILE_FILE"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Activate rbenv in current shell
 | 
				
			||||||
 | 
					  export PATH="$RBENV_DIR/bin:$PATH"
 | 
				
			||||||
 | 
					  eval "$("$RBENV_BIN" init - bash)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Install Ruby version if not already present
 | 
				
			||||||
 | 
					  if "$RBENV_BIN" versions --bare | grep -qx "$RUBY_VERSION"; then
 | 
				
			||||||
 | 
					    msg_ok "Ruby $RUBY_VERSION already installed"
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    $STD msg_info "Installing Ruby $RUBY_VERSION"
 | 
				
			||||||
 | 
					    $STD "$RBENV_BIN" install "$RUBY_VERSION"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Set Ruby version globally
 | 
				
			||||||
 | 
					  "$RBENV_BIN" global "$RUBY_VERSION"
 | 
				
			||||||
 | 
					  hash -r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Optionally install Rails via gem
 | 
				
			||||||
 | 
					  if [[ "$RUBY_INSTALL_RAILS" == "true" ]]; then
 | 
				
			||||||
 | 
					    $STD msg_info "Installing latest Rails via gem"
 | 
				
			||||||
 | 
					    gem install rails
 | 
				
			||||||
 | 
					    msg_ok "Rails $(rails -v) installed"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rm -rf "$TMP_DIR"
 | 
				
			||||||
 | 
					  msg_ok "rbenv stack ready (Ruby $RUBY_VERSION)"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user