From 9ba66d8c049e5e559d34cb73dad8a1d1a9f9b30a Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:36:02 +0100 Subject: [PATCH 01/27] Fix MariaDB installation in fix_almalinux9_comprehensive to check for existing installation - Check for existing MariaDB before attempting installation - Prevents upgrade errors when MariaDB 10.x is already installed - Skips installation if MariaDB is already present - Fixes 'PREIN scriptlet failed' error during installation --- install/install.py | 72 +++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/install/install.py b/install/install.py index e2ab05e25..8caa1532d 100644 --- a/install/install.py +++ b/install/install.py @@ -345,40 +345,48 @@ class preFlightsChecks: self.stdOut(f"Successfully installed alternative: {alt_package}", 1) break - # Install MariaDB with enhanced AlmaLinux 9.6 support - self.stdOut("Installing MariaDB for AlmaLinux 9.6...", 1) + # Check if MariaDB is already installed before attempting installation + is_installed, installed_version, major_minor = self.checkExistingMariaDB() - # Try multiple installation methods for maximum compatibility - mariadb_commands = [ - "dnf install -y mariadb-server mariadb-devel mariadb-client --skip-broken --nobest", - "dnf install -y mariadb-server mariadb-devel mariadb-client --allowerasing", - "dnf install -y mariadb-server mariadb-devel --skip-broken --nobest --allowerasing", - "dnf install -y mariadb-server --skip-broken --nobest --allowerasing" - ] - - mariadb_installed = False - for cmd in mariadb_commands: - try: - result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) - if result.returncode == 0: + if is_installed: + self.stdOut(f"MariaDB/MySQL is already installed (version: {installed_version}), skipping installation", 1) + mariadb_installed = True + else: + # Install MariaDB with enhanced AlmaLinux 9.6 support + self.stdOut("Installing MariaDB for AlmaLinux 9.6...", 1) + + # Try multiple installation methods for maximum compatibility + mariadb_commands = [ + "dnf install -y mariadb-server mariadb-devel mariadb-client --skip-broken --nobest", + "dnf install -y mariadb-server mariadb-devel mariadb-client --allowerasing", + "dnf install -y mariadb-server mariadb-devel --skip-broken --nobest --allowerasing", + "dnf install -y mariadb-server --skip-broken --nobest --allowerasing" + ] + + mariadb_installed = False + for cmd in mariadb_commands: + try: + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) + if result.returncode == 0: + mariadb_installed = True + self.stdOut(f"MariaDB installed successfully with command: {cmd}", 1) + break + except subprocess.TimeoutExpired: + self.stdOut(f"Timeout installing MariaDB with command: {cmd}", 0) + continue + except Exception as e: + self.stdOut(f"Error installing MariaDB with command: {cmd} - {str(e)}", 0) + continue + + if not mariadb_installed: + self.stdOut("MariaDB installation failed, trying MySQL as fallback...", 0) + try: + command = "dnf install -y mysql-server mysql-devel --skip-broken --nobest --allowerasing" + self.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.stdOut("MySQL installed as fallback for MariaDB", 1) mariadb_installed = True - self.stdOut(f"MariaDB installed successfully with command: {cmd}", 1) - break - except subprocess.TimeoutExpired: - self.stdOut(f"Timeout installing MariaDB with command: {cmd}", 0) - continue - except Exception as e: - self.stdOut(f"Error installing MariaDB with command: {cmd} - {str(e)}", 0) - continue - - if not mariadb_installed: - self.stdOut("MariaDB installation failed, trying MySQL as fallback...", 0) - try: - command = "dnf install -y mysql-server mysql-devel --skip-broken --nobest --allowerasing" - self.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - self.stdOut("MySQL installed as fallback for MariaDB", 1) - except: - self.stdOut("Both MariaDB and MySQL installation failed", 0) + except: + self.stdOut("Both MariaDB and MySQL installation failed", 0) # Install additional required packages self.stdOut("Installing additional required packages...", 1) From 273e3ecdc34e448eddee64b64488084f19871497 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:41:39 +0100 Subject: [PATCH 02/27] Add MariaDB check before repository setup in installMySQL - Check if MariaDB is already installed before setting up 12.1 repository - Skip repository setup if MariaDB 10.x is installed to avoid upgrade conflicts - Prevents 'PREIN scriptlet failed' error when installer tries to upgrade - Uses existing MariaDB installation if detected --- install/install.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/install/install.py b/install/install.py index 8caa1532d..e36dd99c5 100644 --- a/install/install.py +++ b/install/install.py @@ -1667,6 +1667,26 @@ module cyberpanel_ols { else: # RHEL-based MariaDB installation + # Check if MariaDB is already installed before setting up repository + is_installed, installed_version, major_minor = self.checkExistingMariaDB() + + if is_installed: + self.stdOut(f"MariaDB/MySQL is already installed (version: {installed_version}), skipping installation", 1) + # Don't set up 12.1 repository if 10.x is installed to avoid upgrade issues + if major_minor and major_minor != "unknown": + try: + major_ver = float(major_minor) + if major_ver < 12.0: + self.stdOut("Skipping MariaDB 12.1 repository setup to avoid upgrade conflicts", 1) + self.stdOut("Using existing MariaDB installation", 1) + self.startMariaDB() + self.changeMYSQLRootPassword() + self.fixMariaDB() + return True + except (ValueError, TypeError): + pass + + # Set up MariaDB 12.1 repository only if not already installed command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1' self.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) From bd570c563b7f28dbec5e6eeef8afbed9585092b3 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:42:12 +0100 Subject: [PATCH 03/27] Add function to disable MariaDB 12.1 repository when 10.x is installed - Prevents upgrade attempts in Pre_Install_Required_Components - Called early in installation process before repository setup - Disables MariaDB 12.1 repository files if MariaDB 10.x is detected - Fixes 'PREIN scriptlet failed' error during installation --- install/install.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/install/install.py b/install/install.py index e36dd99c5..f3b0c7f39 100644 --- a/install/install.py +++ b/install/install.py @@ -1459,6 +1459,52 @@ module cyberpanel_ols { except: return False + def disableMariaDB12RepositoryIfNeeded(self): + """Disable MariaDB 12.1 repository if MariaDB 10.x is already installed to prevent upgrade attempts""" + try: + is_installed, installed_version, major_minor = self.checkExistingMariaDB() + + if is_installed and major_minor and major_minor != "unknown": + try: + major_ver = float(major_minor) + if major_ver < 12.0: + # MariaDB 10.x is installed, disable 12.1 repository to prevent upgrade attempts + self.stdOut(f"MariaDB {installed_version} detected, disabling MariaDB 12.1 repository to prevent upgrade conflicts", 1) + + # Disable MariaDB 12.1 repository + repo_files = [ + '/etc/yum.repos.d/mariadb-main.repo', + '/etc/yum.repos.d/mariadb.repo', + '/etc/yum.repos.d/mariadb-12.1.repo' + ] + + for repo_file in repo_files: + if os.path.exists(repo_file): + try: + # Read the file + with open(repo_file, 'r') as f: + content = f.read() + + # Disable all MariaDB repositories + content = re.sub(r'^(\[.*mariadb.*\])', r'\1\nenabled=0', content, flags=re.MULTILINE | re.IGNORECASE) + + # Write back + with open(repo_file, 'w') as f: + f.write(content) + + self.stdOut(f"Disabled MariaDB repository in {repo_file}", 1) + except Exception as e: + self.stdOut(f"Warning: Could not disable repository {repo_file}: {e}", 1) + + return True + except (ValueError, TypeError): + pass + + return False + except Exception as e: + self.stdOut(f"Warning: Error checking MariaDB repository: {e}", 1) + return False + def checkExistingMariaDB(self): """Check if MariaDB/MySQL is already installed and return version info""" try: @@ -6301,6 +6347,10 @@ def main(): # Apply AlmaLinux 9 comprehensive fixes first if needed if checks.is_almalinux9(): checks.fix_almalinux9_comprehensive() + + # Disable MariaDB 12.1 repository if MariaDB 10.x is already installed + # This prevents upgrade attempts in Pre_Install_Required_Components + checks.disableMariaDB12RepositoryIfNeeded() # Install core services in the correct order checks.installLiteSpeed(ent, serial) From 98ec16f7143656e3e9b8e896d35e83528a2fe54a Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:42:34 +0100 Subject: [PATCH 04/27] Call disableMariaDB12RepositoryIfNeeded in fix_almalinux9_comprehensive - Ensures MariaDB 12.1 repository is disabled early in the process - Called before Pre_Install_Required_Components runs - Prevents upgrade attempts when MariaDB 10.x is already installed --- install/install.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/install/install.py b/install/install.py index f3b0c7f39..a1199050a 100644 --- a/install/install.py +++ b/install/install.py @@ -345,6 +345,10 @@ class preFlightsChecks: self.stdOut(f"Successfully installed alternative: {alt_package}", 1) break + # Disable MariaDB 12.1 repository if MariaDB 10.x is already installed + # This prevents upgrade attempts in Pre_Install_Required_Components + self.disableMariaDB12RepositoryIfNeeded() + # Check if MariaDB is already installed before attempting installation is_installed, installed_version, major_minor = self.checkExistingMariaDB() From 65af295f0ea1cefaa29f877c5403d26c7437ee7d Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:48:45 +0100 Subject: [PATCH 05/27] Improve MariaDB repository disabling and add dnf exclude - Enhanced repository file detection using glob - Better repository file parsing to disable MariaDB sections - Always add MariaDB-server to dnf excludes to prevent upgrades - Handles both existing and new dnf.conf files - Prevents MariaDB upgrade attempts in Pre_Install_Required_Components --- install/install.py | 90 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/install/install.py b/install/install.py index a1199050a..d11718ad2 100644 --- a/install/install.py +++ b/install/install.py @@ -1474,31 +1474,102 @@ module cyberpanel_ols { if major_ver < 12.0: # MariaDB 10.x is installed, disable 12.1 repository to prevent upgrade attempts self.stdOut(f"MariaDB {installed_version} detected, disabling MariaDB 12.1 repository to prevent upgrade conflicts", 1) + logging.InstallLog.writeToFile(f"MariaDB {installed_version} detected, disabling MariaDB 12.1 repository") - # Disable MariaDB 12.1 repository + # Disable MariaDB 12.1 repository - check all possible repo file locations repo_files = [ '/etc/yum.repos.d/mariadb-main.repo', '/etc/yum.repos.d/mariadb.repo', - '/etc/yum.repos.d/mariadb-12.1.repo' + '/etc/yum.repos.d/mariadb-12.1.repo', + '/etc/yum.repos.d/mariadb-main.repo.bak' ] + # Also check for any mariadb repo files + import glob + repo_files.extend(glob.glob('/etc/yum.repos.d/*mariadb*.repo')) + + disabled_any = False for repo_file in repo_files: if os.path.exists(repo_file): try: # Read the file with open(repo_file, 'r') as f: - content = f.read() + lines = f.readlines() - # Disable all MariaDB repositories - content = re.sub(r'^(\[.*mariadb.*\])', r'\1\nenabled=0', content, flags=re.MULTILINE | re.IGNORECASE) + # Modify the file to disable all MariaDB repositories + modified = False + new_lines = [] + in_mariadb_section = False - # Write back - with open(repo_file, 'w') as f: - f.write(content) + for line in lines: + # Check if we're entering a MariaDB repository section + if line.strip().startswith('[') and 'mariadb' in line.lower(): + in_mariadb_section = True + new_lines.append(line) + # Add enabled=0 if not already present + if 'enabled' not in line.lower(): + new_lines.append('enabled=0\n') + modified = True + elif in_mariadb_section: + # If we see enabled=1, change it to enabled=0 + if line.strip().startswith('enabled=') and 'enabled=0' not in line.lower(): + new_lines.append('enabled=0\n') + modified = True + elif line.strip().startswith('['): + # New section, exit MariaDB section + in_mariadb_section = False + new_lines.append(line) + else: + new_lines.append(line) + else: + new_lines.append(line) + + # Write back if modified + if modified: + with open(repo_file, 'w') as f: + f.writelines(new_lines) + self.stdOut(f"Disabled MariaDB repository in {repo_file}", 1) + logging.InstallLog.writeToFile(f"Disabled MariaDB repository in {repo_file}") + disabled_any = True - self.stdOut(f"Disabled MariaDB repository in {repo_file}", 1) except Exception as e: self.stdOut(f"Warning: Could not disable repository {repo_file}: {e}", 1) + logging.InstallLog.writeToFile(f"Warning: Could not disable repository {repo_file}: {e}") + + # Always exclude MariaDB-server from dnf/yum operations to prevent upgrades + try: + # Add exclude to dnf.conf + dnf_conf = '/etc/dnf/dnf.conf' + exclude_line = 'exclude=MariaDB-server' + + if os.path.exists(dnf_conf): + with open(dnf_conf, 'r') as f: + dnf_content = f.read() + + # Check if exclude line already exists + if exclude_line not in dnf_content: + # Check if there's already an exclude line + if 'exclude=' in dnf_content: + # Append to existing exclude line + dnf_content = re.sub(r'(exclude=.*)', r'\1 MariaDB-server', dnf_content) + else: + # Add new exclude line + dnf_content = dnf_content.rstrip() + '\n' + exclude_line + '\n' + + with open(dnf_conf, 'w') as f: + f.write(dnf_content) + self.stdOut("Added MariaDB-server to dnf excludes to prevent upgrade", 1) + logging.InstallLog.writeToFile("Added MariaDB-server to dnf excludes") + else: + # Create dnf.conf with exclude + with open(dnf_conf, 'w') as f: + f.write('[main]\n') + f.write(exclude_line + '\n') + self.stdOut("Created dnf.conf with MariaDB-server exclude", 1) + logging.InstallLog.writeToFile("Created dnf.conf with MariaDB-server exclude") + except Exception as e: + self.stdOut(f"Warning: Could not add exclude to dnf.conf: {e}", 1) + logging.InstallLog.writeToFile(f"Warning: Could not add exclude to dnf.conf: {e}") return True except (ValueError, TypeError): @@ -1507,6 +1578,7 @@ module cyberpanel_ols { return False except Exception as e: self.stdOut(f"Warning: Error checking MariaDB repository: {e}", 1) + logging.InstallLog.writeToFile(f"Warning: Error checking MariaDB repository: {e}") return False def checkExistingMariaDB(self): From ba43d72649dcd4136827e43dee4dfb3888712e9b Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:49:17 +0100 Subject: [PATCH 06/27] Call disableMariaDB12RepositoryIfNeeded earlier in main() function - Called immediately after apply_os_specific_fixes() - Runs before Pre_Install_Required_Components attempts MariaDB installation - Ensures dnf exclude is set before any package operations - Prevents MariaDB upgrade attempts --- install/install.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/install/install.py b/install/install.py index d11718ad2..89a3fb783 100644 --- a/install/install.py +++ b/install/install.py @@ -6396,6 +6396,10 @@ def main(): # Apply OS-specific fixes early in the installation process checks.apply_os_specific_fixes() + + # CRITICAL: Disable MariaDB 12.1 repository and add dnf exclude BEFORE any MariaDB installation attempts + # This must run before Pre_Install_Required_Components tries to install MariaDB + checks.disableMariaDB12RepositoryIfNeeded() # Ensure MySQL password file is created early to prevent FileNotFoundError checks.ensure_mysql_password_file() From e2033b1f342402f9ad455f2a56b357ee07da9614 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 21:49:46 +0100 Subject: [PATCH 07/27] Add dnf exclude for MariaDB-server in cyberpanel.sh before installer runs - Checks for existing MariaDB 10.x installation - Adds MariaDB-server to dnf excludes BEFORE Pre_Install_Setup_Repository - Prevents upgrade attempts in Pre_Install_Required_Components - Runs early in install_cyberpanel_direct() function --- cyberpanel.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cyberpanel.sh b/cyberpanel.sh index f5441b811..194c3d140 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -609,6 +609,44 @@ install_cyberpanel_direct() { mkdir -p "$temp_dir" cd "$temp_dir" || return 1 + # CRITICAL: Disable MariaDB 12.1 repository and add dnf exclude if MariaDB 10.x is installed + # This must be done BEFORE Pre_Install_Setup_Repository runs + if command -v rpm >/dev/null 2>&1; then + # Check if MariaDB 10.x is installed + if rpm -qa | grep -qiE "^(mariadb-server|mysql-server|MariaDB-server)" 2>/dev/null; then + local mariadb_version=$(mysql --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + if [ -n "$mariadb_version" ]; then + local major_ver=$(echo "$mariadb_version" | cut -d. -f1) + local minor_ver=$(echo "$mariadb_version" | cut -d. -f2) + + # Check if it's MariaDB 10.x (major version < 12) + if [ "$major_ver" -lt 12 ]; then + print_status "MariaDB $mariadb_version detected, adding dnf exclude to prevent upgrade attempts" + + # Add MariaDB-server to dnf excludes + local dnf_conf="/etc/dnf/dnf.conf" + if [ -f "$dnf_conf" ]; then + if ! grep -q "exclude=MariaDB-server" "$dnf_conf" 2>/dev/null; then + if grep -q "^exclude=" "$dnf_conf" 2>/dev/null; then + # Append to existing exclude line + sed -i 's/^exclude=\(.*\)/exclude=\1 MariaDB-server/' "$dnf_conf" + else + # Add new exclude line + echo "exclude=MariaDB-server" >> "$dnf_conf" + fi + print_status "Added MariaDB-server to dnf excludes" + fi + else + # Create dnf.conf with exclude + echo "[main]" > "$dnf_conf" + echo "exclude=MariaDB-server" >> "$dnf_conf" + print_status "Created dnf.conf with MariaDB-server exclude" + fi + fi + fi + fi + fi + # Download the working CyberPanel installation files # Use master3395 fork which has our fixes echo "Downloading from: https://raw.githubusercontent.com/master3395/cyberpanel/v2.5.5-dev/cyberpanel.sh" From cc62657026d47b8cf046ad836440decd0a6f4a79 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:01:12 +0100 Subject: [PATCH 08/27] Improve dnf exclude syntax and add yum.conf exclude - Use MariaDB-server* with wildcard for better matching - Ensure exclude is in [main] section of dnf.conf - Also add exclude to yum.conf for compatibility - Better handling of existing exclude lines --- cyberpanel.sh | 53 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 194c3d140..54af7edc7 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -623,24 +623,55 @@ install_cyberpanel_direct() { if [ "$major_ver" -lt 12 ]; then print_status "MariaDB $mariadb_version detected, adding dnf exclude to prevent upgrade attempts" - # Add MariaDB-server to dnf excludes + # Add MariaDB-server to dnf excludes (multiple formats for compatibility) local dnf_conf="/etc/dnf/dnf.conf" + local exclude_added=false + if [ -f "$dnf_conf" ]; then - if ! grep -q "exclude=MariaDB-server" "$dnf_conf" 2>/dev/null; then - if grep -q "^exclude=" "$dnf_conf" 2>/dev/null; then - # Append to existing exclude line - sed -i 's/^exclude=\(.*\)/exclude=\1 MariaDB-server/' "$dnf_conf" - else - # Add new exclude line - echo "exclude=MariaDB-server" >> "$dnf_conf" + # Check if [main] section exists + if grep -q "^\[main\]" "$dnf_conf" 2>/dev/null; then + # [main] section exists, add exclude there + if ! grep -q "exclude=.*MariaDB-server" "$dnf_conf" 2>/dev/null; then + if grep -q "^exclude=" "$dnf_conf" 2>/dev/null; then + # Append to existing exclude line in [main] section + sed -i '/^\[main\]/,/^\[/ { /^exclude=/ s/$/ MariaDB-server*/ }' "$dnf_conf" + else + # Add new exclude line after [main] + sed -i '/^\[main\]/a exclude=MariaDB-server*' "$dnf_conf" + fi + exclude_added=true + fi + else + # No [main] section, add it with exclude + if ! grep -q "exclude=.*MariaDB-server" "$dnf_conf" 2>/dev/null; then + echo "" >> "$dnf_conf" + echo "[main]" >> "$dnf_conf" + echo "exclude=MariaDB-server*" >> "$dnf_conf" + exclude_added=true fi - print_status "Added MariaDB-server to dnf excludes" fi else # Create dnf.conf with exclude echo "[main]" > "$dnf_conf" - echo "exclude=MariaDB-server" >> "$dnf_conf" - print_status "Created dnf.conf with MariaDB-server exclude" + echo "exclude=MariaDB-server*" >> "$dnf_conf" + exclude_added=true + fi + + if [ "$exclude_added" = true ]; then + print_status "Added MariaDB-server* to dnf excludes in $dnf_conf" + fi + + # Also add to yum.conf for compatibility + local yum_conf="/etc/yum.conf" + if [ -f "$yum_conf" ]; then + if ! grep -q "exclude=.*MariaDB-server" "$yum_conf" 2>/dev/null; then + if grep -q "^exclude=" "$yum_conf" 2>/dev/null; then + sed -i 's/^exclude=\(.*\)/exclude=\1 MariaDB-server*/' "$yum_conf" + else + echo "exclude=MariaDB-server*" >> "$yum_conf" + fi + print_status "Added MariaDB-server* to yum excludes" + fi fi fi fi From 5a448acd64ca4c0990f9247b46e625faed00205e Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:01:53 +0100 Subject: [PATCH 09/27] Add background monitor to disable MariaDB repositories after they're created - Creates function to disable MariaDB repository files - Starts background process to monitor and disable repos as they're created - Calls disable function right before installer runs - Stops monitor after installation completes - Prevents MariaDB upgrade attempts even if repository is set up --- cyberpanel.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/cyberpanel.sh b/cyberpanel.sh index 54af7edc7..ea6f95008 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -673,6 +673,42 @@ install_cyberpanel_direct() { print_status "Added MariaDB-server* to yum excludes" fi fi + + # Create a function to disable MariaDB repositories (will be called after repository setup) + disable_mariadb_repos() { + local repo_files=( + "/etc/yum.repos.d/mariadb-main.repo" + "/etc/yum.repos.d/mariadb.repo" + "/etc/yum.repos.d/mariadb-12.1.repo" + ) + + for repo_file in "${repo_files[@]}"; do + if [ -f "$repo_file" ]; then + # Disable all MariaDB repository sections + sed -i '/^\[.*mariadb.*\]/I,/^\[/ { /^enabled\s*=/ s/=.*/=0/; /^\[.*mariadb.*\]/I { /enabled/!a enabled=0 +} }' "$repo_file" 2>/dev/null || \ + sed -i 's/^enabled\s*=\s*1/enabled=0/g' "$repo_file" 2>/dev/null + print_status "Disabled MariaDB repository in $repo_file" + fi + done + } + + # Export function so it can be called from installer + export -f disable_mariadb_repos + export MARIADB_VERSION="$mariadb_version" + + # Also set up a background process to monitor and disable repos + ( + while [ ! -f /tmp/cyberpanel_install_complete ]; do + sleep 2 + if [ -f /etc/yum.repos.d/mariadb-main.repo ] || [ -f /etc/yum.repos.d/mariadb.repo ]; then + disable_mariadb_repos + fi + done + ) & + local monitor_pid=$! + echo "$monitor_pid" > /tmp/cyberpanel_repo_monitor.pid + print_status "Started background process to monitor and disable MariaDB repositories" fi fi fi @@ -785,11 +821,31 @@ install_cyberpanel_direct() { installer_path="$(pwd)/$installer_script" fi + # If MariaDB 10.x is installed, disable repositories right before running installer + if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then + # Call the disable function one more time before installer runs + if type disable_mariadb_repos >/dev/null 2>&1; then + disable_mariadb_repos + fi + fi + if [ "$DEBUG_MODE" = true ]; then bash "$installer_path" --debug 2>&1 | tee /var/log/CyberPanel/install_output.log else bash "$installer_path" 2>&1 | tee /var/log/CyberPanel/install_output.log fi + + local install_exit_code=${PIPESTATUS[0]} + + # Stop the repository monitor + if [ -f /tmp/cyberpanel_repo_monitor.pid ]; then + local monitor_pid=$(cat /tmp/cyberpanel_repo_monitor.pid 2>/dev/null) + if [ -n "$monitor_pid" ] && kill -0 "$monitor_pid" 2>/dev/null; then + kill "$monitor_pid" 2>/dev/null + fi + rm -f /tmp/cyberpanel_repo_monitor.pid + fi + touch /tmp/cyberpanel_install_complete 2>/dev/null || true local install_exit_code=${PIPESTATUS[0]} From e71a097cf9347ffa80062578e27c5129fccd5281 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:02:14 +0100 Subject: [PATCH 10/27] Fix sed commands to properly disable MariaDB repositories - Simplified repository disabling logic - Ensures enabled=0 is set in all MariaDB repository sections - Handles cases where enabled line doesn't exist - More robust file detection using find command --- cyberpanel.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index ea6f95008..e3568edcf 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -682,13 +682,27 @@ install_cyberpanel_direct() { "/etc/yum.repos.d/mariadb-12.1.repo" ) + # Also check for any mariadb repo files + repo_files+=($(find /etc/yum.repos.d -name "*mariadb*.repo" 2>/dev/null)) + for repo_file in "${repo_files[@]}"; do if [ -f "$repo_file" ]; then - # Disable all MariaDB repository sections - sed -i '/^\[.*mariadb.*\]/I,/^\[/ { /^enabled\s*=/ s/=.*/=0/; /^\[.*mariadb.*\]/I { /enabled/!a enabled=0 -} }' "$repo_file" 2>/dev/null || \ + # Disable all enabled=1 lines in MariaDB repository sections + # First, change enabled=1 to enabled=0 sed -i 's/^enabled\s*=\s*1/enabled=0/g' "$repo_file" 2>/dev/null - print_status "Disabled MariaDB repository in $repo_file" + + # If there's a MariaDB section without enabled line, add enabled=0 + # This is a simpler approach - just ensure all MariaDB repos are disabled + if grep -qi "mariadb" "$repo_file" 2>/dev/null; then + # Add enabled=0 after each [mariadb...] section header if not present + sed -i '/^\[.*mariadb.*\]/I { N; /enabled/! { s/$/\nenabled=0/; } }' "$repo_file" 2>/dev/null || \ + sed -i '/^\[.*mariadb.*\]/I a enabled=0' "$repo_file" 2>/dev/null + + # Final check - ensure enabled=0 exists in MariaDB sections + if ! grep -qi "enabled.*0" "$repo_file" 2>/dev/null; then + sed -i 's/^\(\[.*mariadb.*\]\)/\1\nenabled=0/I' "$repo_file" 2>/dev/null + fi + fi fi done } From 09800e12fc80ea2648d6f4abd856c225ba479f03 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:02:44 +0100 Subject: [PATCH 11/27] Use Python to properly disable MariaDB repositories with fallback - Uses Python for more reliable repository file parsing - Handles MariaDB 12.1 repository sections correctly - Falls back to renaming repository files if Python fails - More robust than sed for complex repository file formats --- cyberpanel.sh | 65 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index e3568edcf..453dff4c7 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -683,25 +683,60 @@ install_cyberpanel_direct() { ) # Also check for any mariadb repo files - repo_files+=($(find /etc/yum.repos.d -name "*mariadb*.repo" 2>/dev/null)) + while IFS= read -r repo_file; do + repo_files+=("$repo_file") + done < <(find /etc/yum.repos.d -name "*mariadb*.repo" 2>/dev/null) for repo_file in "${repo_files[@]}"; do - if [ -f "$repo_file" ]; then - # Disable all enabled=1 lines in MariaDB repository sections - # First, change enabled=1 to enabled=0 + if [ -f "$repo_file" ] && [ -n "$repo_file" ]; then + # First, try to disable by setting enabled=0 sed -i 's/^enabled\s*=\s*1/enabled=0/g' "$repo_file" 2>/dev/null - # If there's a MariaDB section without enabled line, add enabled=0 - # This is a simpler approach - just ensure all MariaDB repos are disabled - if grep -qi "mariadb" "$repo_file" 2>/dev/null; then - # Add enabled=0 after each [mariadb...] section header if not present - sed -i '/^\[.*mariadb.*\]/I { N; /enabled/! { s/$/\nenabled=0/; } }' "$repo_file" 2>/dev/null || \ - sed -i '/^\[.*mariadb.*\]/I a enabled=0' "$repo_file" 2>/dev/null - - # Final check - ensure enabled=0 exists in MariaDB sections - if ! grep -qi "enabled.*0" "$repo_file" 2>/dev/null; then - sed -i 's/^\(\[.*mariadb.*\]\)/\1\nenabled=0/I' "$repo_file" 2>/dev/null - fi + # If file contains MariaDB 12.1 references, disable or remove it + if grep -qi "mariadb.*12\|12.*mariadb\|mariadb-main" "$repo_file" 2>/dev/null; then + # Try to add enabled=0 to each [mariadb...] section + python3 -c " +import re +import sys +try: + with open('$repo_file', 'r') as f: + content = f.read() + + # Replace enabled=1 with enabled=0 + content = re.sub(r'(enabled\s*=\s*)1', r'\g<1>0', content, flags=re.IGNORECASE) + + # Add enabled=0 after [mariadb...] sections if not present + lines = content.split('\n') + new_lines = [] + in_mariadb_section = False + has_enabled = False + + for i, line in enumerate(lines): + new_lines.append(line) + if re.match(r'^\s*\[.*mariadb.*\]', line, re.IGNORECASE): + in_mariadb_section = True + has_enabled = False + elif in_mariadb_section: + if re.match(r'^\s*enabled\s*=', line, re.IGNORECASE): + has_enabled = True + elif re.match(r'^\s*\[', line) and not re.match(r'^\s*\[.*mariadb.*\]', line, re.IGNORECASE): + if not has_enabled: + new_lines.insert(-1, 'enabled=0') + in_mariadb_section = False + has_enabled = False + + if in_mariadb_section and not has_enabled: + new_lines.append('enabled=0') + + with open('$repo_file', 'w') as f: + f.write('\n'.join(new_lines)) +except: + # Fallback: just rename the file + import os + os.rename('$repo_file', '${repo_file}.disabled') +" 2>/dev/null || \ + # Fallback: rename the file to disable it + mv "$repo_file" "${repo_file}.disabled" 2>/dev/null || true fi fi done From 70a4182962b4b7741726b4f261842162932fb8cf Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:28:30 +0100 Subject: [PATCH 12/27] Patch downloaded installer script to exclude MariaDB-server from dnf/yum commands - Modifies installer script after download but before execution - Adds --exclude=MariaDB-server* to all dnf/yum install commands - Prevents MariaDB upgrade attempts in Pre_Install_Required_Components - Works even if repository is set up and enabled --- cyberpanel.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cyberpanel.sh b/cyberpanel.sh index 453dff4c7..0af6fe80b 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -783,6 +783,28 @@ except: return 1 fi + # CRITICAL: Patch the installer script to skip MariaDB installation if 10.x is already installed + if [ -n "$MARIADB_VERSION" ] && [ "$major_ver" -lt 12 ] 2>/dev/null; then + print_status "Patching installer script to skip MariaDB installation..." + + # Create a backup + cp cyberpanel_installer.sh cyberpanel_installer.sh.backup + + # Patch dnf install commands to exclude MariaDB-server + # This prevents the installer from trying to upgrade MariaDB + sed -i 's/dnf install\([^;]*\)mariadb-server/dnf install\1--exclude=MariaDB-server* mariadb-server/g' cyberpanel_installer.sh 2>/dev/null + sed -i 's/dnf install\([^;]*\)MariaDB-server/dnf install\1--exclude=MariaDB-server* MariaDB-server/g' cyberpanel_installer.sh 2>/dev/null + + # Also patch yum commands + sed -i 's/yum install\([^;]*\)mariadb-server/yum install\1--exclude=MariaDB-server* mariadb-server/g' cyberpanel_installer.sh 2>/dev/null + sed -i 's/yum install\([^;]*\)MariaDB-server/yum install\1--exclude=MariaDB-server* MariaDB-server/g' cyberpanel_installer.sh 2>/dev/null + + # Add exclude to any dnf/yum install command that might install MariaDB + sed -i 's/\(dnf\|yum\) install -y\([^;]*\)$/\1 install -y --exclude=MariaDB-server*\2/g' cyberpanel_installer.sh 2>/dev/null + + print_status "Installer script patched to exclude MariaDB-server from installation" + fi + # Make script executable and verify chmod 755 cyberpanel_installer.sh 2>/dev/null || true if [ ! -x "cyberpanel_installer.sh" ]; then From cb2ec327ce155d3b3df5ab035de8028933e9f089 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:29:01 +0100 Subject: [PATCH 13/27] Improve installer script patching with Python for better reliability - Uses Python to properly parse and modify installer script - Handles multiple patterns for dnf/yum install commands - Adds --exclude=MariaDB-server* to all relevant commands - Falls back to sed if Python fails - More robust than simple sed replacements --- cyberpanel.sh | 69 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 0af6fe80b..1c831195b 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -790,17 +790,66 @@ except: # Create a backup cp cyberpanel_installer.sh cyberpanel_installer.sh.backup - # Patch dnf install commands to exclude MariaDB-server - # This prevents the installer from trying to upgrade MariaDB - sed -i 's/dnf install\([^;]*\)mariadb-server/dnf install\1--exclude=MariaDB-server* mariadb-server/g' cyberpanel_installer.sh 2>/dev/null - sed -i 's/dnf install\([^;]*\)MariaDB-server/dnf install\1--exclude=MariaDB-server* MariaDB-server/g' cyberpanel_installer.sh 2>/dev/null + # Use Python to properly patch the installer script + python3 << 'PYTHON_PATCH' 2>/dev/null || { +import re +import sys + +try: + with open('cyberpanel_installer.sh', 'r') as f: + content = f.read() + + original_content = content + + # Pattern 1: dnf/yum install commands with mariadb-server/MariaDB-server + # Add --exclude=MariaDB-server* before mariadb-server packages + patterns = [ + (r'(dnf install[^;]*?)(mariadb-server|MariaDB-server)', r'\1--exclude=MariaDB-server* \2'), + (r'(yum install[^;]*?)(mariadb-server|MariaDB-server)', r'\1--exclude=MariaDB-server* \2'), + (r'(dnf install[^;]*?)(\s+)(mariadb-server|MariaDB-server)', r'\1\2--exclude=MariaDB-server* \3'), + (r'(yum install[^;]*?)(\s+)(mariadb-server|MariaDB-server)', r'\1\2--exclude=MariaDB-server* \3'), + ] + + for pattern, replacement in patterns: + content = re.sub(pattern, replacement, content, flags=re.IGNORECASE) + + # Pattern 2: If dnf/yum install doesn't have --exclude yet, add it + # This catches commands like "dnf install -y mariadb-server mariadb-devel" + lines = content.split('\n') + new_lines = [] + for line in lines: + # Check if line contains dnf/yum install and mariadb-server but not --exclude + if re.search(r'(dnf|yum)\s+install', line, re.IGNORECASE) and \ + re.search(r'mariadb-server|MariaDB-server', line, re.IGNORECASE) and \ + '--exclude=MariaDB-server' not in line: + # Add --exclude=MariaDB-server* after install flags but before packages + line = re.sub( + r'((?:dnf|yum)\s+install\s+(?:-[^\s]*\s*)*)', + r'\1--exclude=MariaDB-server* ', + line, + flags=re.IGNORECASE + ) + new_lines.append(line) + + content = '\n'.join(new_lines) + + # Only write if content changed + if content != original_content: + with open('cyberpanel_installer.sh', 'w') as f: + f.write(content) + print("Installer script patched successfully") + else: + print("No changes needed in installer script") - # Also patch yum commands - sed -i 's/yum install\([^;]*\)mariadb-server/yum install\1--exclude=MariaDB-server* mariadb-server/g' cyberpanel_installer.sh 2>/dev/null - sed -i 's/yum install\([^;]*\)MariaDB-server/yum install\1--exclude=MariaDB-server* MariaDB-server/g' cyberpanel_installer.sh 2>/dev/null - - # Add exclude to any dnf/yum install command that might install MariaDB - sed -i 's/\(dnf\|yum\) install -y\([^;]*\)$/\1 install -y --exclude=MariaDB-server*\2/g' cyberpanel_installer.sh 2>/dev/null +except Exception as e: + print(f"Error patching installer script: {e}") + sys.exit(1) +PYTHON_PATCH + # Fallback: Simple sed-based patching if Python fails + sed -i 's/\(dnf\|yum\) install\([^;]*\)mariadb-server/\1 install\2--exclude=MariaDB-server* mariadb-server/gi' cyberpanel_installer.sh 2>/dev/null + sed -i 's/\(dnf\|yum\) install\([^;]*\)MariaDB-server/\1 install\2--exclude=MariaDB-server* MariaDB-server/gi' cyberpanel_installer.sh 2>/dev/null + print_status "Installer script patched (fallback method)" + } print_status "Installer script patched to exclude MariaDB-server from installation" fi From 730cbe68791fbb9e255842def483b2285b3b1a9b Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:29:33 +0100 Subject: [PATCH 14/27] Fix Python script syntax for installer patching - Uses python3 -c instead of heredoc for better compatibility - Simplified regex patterns for more reliable matching - Better error handling and fallback to sed - Properly adds --exclude=MariaDB-server* to dnf/yum install commands --- cyberpanel.sh | 64 +++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 1c831195b..4822e91b6 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -791,7 +791,7 @@ except: cp cyberpanel_installer.sh cyberpanel_installer.sh.backup # Use Python to properly patch the installer script - python3 << 'PYTHON_PATCH' 2>/dev/null || { + python3 -c " import re import sys @@ -801,55 +801,49 @@ try: original_content = content - # Pattern 1: dnf/yum install commands with mariadb-server/MariaDB-server - # Add --exclude=MariaDB-server* before mariadb-server packages - patterns = [ - (r'(dnf install[^;]*?)(mariadb-server|MariaDB-server)', r'\1--exclude=MariaDB-server* \2'), - (r'(yum install[^;]*?)(mariadb-server|MariaDB-server)', r'\1--exclude=MariaDB-server* \2'), - (r'(dnf install[^;]*?)(\s+)(mariadb-server|MariaDB-server)', r'\1\2--exclude=MariaDB-server* \3'), - (r'(yum install[^;]*?)(\s+)(mariadb-server|MariaDB-server)', r'\1\2--exclude=MariaDB-server* \3'), - ] + # Pattern: Add --exclude=MariaDB-server* to dnf/yum install commands that install mariadb-server + # Match: (dnf|yum) install [flags] [packages including mariadb-server] + def add_exclude(match): + cmd = match.group(0) + # Check if --exclude is already present + if '--exclude=MariaDB-server' in cmd: + return cmd + # Add --exclude=MariaDB-server* after install and flags, before packages + return re.sub(r'((?:dnf|yum)\s+install\s+(?:-[^\s]+\s+)*)', r'\1--exclude=MariaDB-server* ', cmd, flags=re.IGNORECASE) - for pattern, replacement in patterns: - content = re.sub(pattern, replacement, content, flags=re.IGNORECASE) + # Find all dnf/yum install commands that mention mariadb-server + content = re.sub( + r'(?:dnf|yum)\s+install[^;]*?mariadb-server[^;]*', + add_exclude, + content, + flags=re.IGNORECASE | re.MULTILINE + ) - # Pattern 2: If dnf/yum install doesn't have --exclude yet, add it - # This catches commands like "dnf install -y mariadb-server mariadb-devel" - lines = content.split('\n') - new_lines = [] - for line in lines: - # Check if line contains dnf/yum install and mariadb-server but not --exclude - if re.search(r'(dnf|yum)\s+install', line, re.IGNORECASE) and \ - re.search(r'mariadb-server|MariaDB-server', line, re.IGNORECASE) and \ - '--exclude=MariaDB-server' not in line: - # Add --exclude=MariaDB-server* after install flags but before packages - line = re.sub( - r'((?:dnf|yum)\s+install\s+(?:-[^\s]*\s*)*)', - r'\1--exclude=MariaDB-server* ', - line, - flags=re.IGNORECASE - ) - new_lines.append(line) - - content = '\n'.join(new_lines) + # Also handle MariaDB-server (capitalized) + content = re.sub( + r'(?:dnf|yum)\s+install[^;]*?MariaDB-server[^;]*', + add_exclude, + content, + flags=re.IGNORECASE | re.MULTILINE + ) # Only write if content changed if content != original_content: with open('cyberpanel_installer.sh', 'w') as f: f.write(content) - print("Installer script patched successfully") + print('Installer script patched successfully') else: - print("No changes needed in installer script") + print('No changes needed in installer script') except Exception as e: - print(f"Error patching installer script: {e}") + print(f'Error patching installer script: {e}') sys.exit(1) -PYTHON_PATCH +" 2>/dev/null && print_status "Installer script patched successfully" || { # Fallback: Simple sed-based patching if Python fails sed -i 's/\(dnf\|yum\) install\([^;]*\)mariadb-server/\1 install\2--exclude=MariaDB-server* mariadb-server/gi' cyberpanel_installer.sh 2>/dev/null sed -i 's/\(dnf\|yum\) install\([^;]*\)MariaDB-server/\1 install\2--exclude=MariaDB-server* MariaDB-server/gi' cyberpanel_installer.sh 2>/dev/null print_status "Installer script patched (fallback method)" - } + } print_status "Installer script patched to exclude MariaDB-server from installation" fi From 368994ab13ba1370a09a135050f0108279d7d380 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:37:50 +0100 Subject: [PATCH 15/27] Use install/install.py directly instead of cyberpanel_installer.sh wrapper - install/install.py is the actual installer with our fixes - cyberpanel_installer.sh is old v2.4.4 wrapper that doesn't support auto-install - This ensures auto-install mode works and uses our fixed installer - Falls back to cyberpanel_installer.sh if install.py not found --- cyberpanel.sh | 102 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 4822e91b6..c7f059a21 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -765,16 +765,24 @@ except: # Download the working CyberPanel installation files # Use master3395 fork which has our fixes + # Try to download the actual installer script (install/install.py) from the repository echo "Downloading from: https://raw.githubusercontent.com/master3395/cyberpanel/v2.5.5-dev/cyberpanel.sh" - # Try development branch first, fallback to stable + + # First, try to download the repository archive to get the correct installer + local archive_url="https://github.com/master3395/cyberpanel/archive/v2.5.5-dev.tar.gz" local installer_url="https://raw.githubusercontent.com/master3395/cyberpanel/v2.5.5-dev/cyberpanel.sh" - # Test if the development branch exists - if ! curl -s --head "$installer_url" | grep -q "200 OK"; then - echo " Development branch not available, falling back to stable" - installer_url="https://raw.githubusercontent.com/master3395/cyberpanel/stable/cyberpanel.sh" - else + # Test if the development branch archive exists + if curl -s --head "$archive_url" | grep -q "200 OK"; then echo " Using development branch (v2.5.5-dev) from master3395/cyberpanel" + else + echo " Development branch archive not available, trying installer script directly..." + # Test if the installer script exists + if ! curl -s --head "$installer_url" | grep -q "200 OK"; then + echo " Development branch not available, falling back to stable" + installer_url="https://raw.githubusercontent.com/master3395/cyberpanel/stable/cyberpanel.sh" + archive_url="https://github.com/master3395/cyberpanel/archive/stable.tar.gz" + fi fi curl --silent -o cyberpanel_installer.sh "$installer_url" 2>/dev/null @@ -919,34 +927,64 @@ except Exception as e: fi echo "" - # Run installer and show live output, capturing the password - # Use bash to execute to avoid permission issues - local installer_script="cyberpanel_installer.sh" - if [ ! -f "$installer_script" ]; then - print_status "ERROR: cyberpanel_installer.sh not found in current directory: $(pwd)" - return 1 - fi - - # Get absolute path to installer script - local installer_path - if [[ "$installer_script" = /* ]]; then - installer_path="$installer_script" - else - installer_path="$(pwd)/$installer_script" - fi - - # If MariaDB 10.x is installed, disable repositories right before running installer - if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then - # Call the disable function one more time before installer runs - if type disable_mariadb_repos >/dev/null 2>&1; then - disable_mariadb_repos + # CRITICAL: Use install/install.py directly instead of cyberpanel_installer.sh + # The cyberpanel_installer.sh is the old wrapper that doesn't support auto-install + # install/install.py is the actual installer that we can control + local installer_py="install/install.py" + if [ -f "$installer_py" ]; then + print_status "Using install/install.py directly for installation" + + # If MariaDB 10.x is installed, disable repositories right before running installer + if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then + # Call the disable function one more time before installer runs + if type disable_mariadb_repos >/dev/null 2>&1; then + disable_mariadb_repos + fi + fi + + # Build installer arguments based on user preferences + local install_args=() + if [ "$DEBUG_MODE" = true ]; then + install_args+=("--debug") + fi + + # Run the Python installer directly + if [ "$DEBUG_MODE" = true ]; then + python3 "$installer_py" "${install_args[@]}" 2>&1 | tee /var/log/CyberPanel/install_output.log + else + python3 "$installer_py" "${install_args[@]}" 2>&1 | tee /var/log/CyberPanel/install_output.log fi - fi - - if [ "$DEBUG_MODE" = true ]; then - bash "$installer_path" --debug 2>&1 | tee /var/log/CyberPanel/install_output.log else - bash "$installer_path" 2>&1 | tee /var/log/CyberPanel/install_output.log + # Fallback to cyberpanel_installer.sh if install.py not found + print_status "WARNING: install/install.py not found, using cyberpanel_installer.sh (may be interactive)" + + local installer_script="cyberpanel_installer.sh" + if [ ! -f "$installer_script" ]; then + print_status "ERROR: cyberpanel_installer.sh not found in current directory: $(pwd)" + return 1 + fi + + # Get absolute path to installer script + local installer_path + if [[ "$installer_script" = /* ]]; then + installer_path="$installer_script" + else + installer_path="$(pwd)/$installer_script" + fi + + # If MariaDB 10.x is installed, disable repositories right before running installer + if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then + # Call the disable function one more time before installer runs + if type disable_mariadb_repos >/dev/null 2>&1; then + disable_mariadb_repos + fi + fi + + if [ "$DEBUG_MODE" = true ]; then + bash "$installer_path" --debug 2>&1 | tee /var/log/CyberPanel/install_output.log + else + bash "$installer_path" 2>&1 | tee /var/log/CyberPanel/install_output.log + fi fi local install_exit_code=${PIPESTATUS[0]} From 703ea3b1bb3652bf12f93c7e81c7d1f0952167db Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:38:32 +0100 Subject: [PATCH 16/27] Pass required arguments to install.py for non-interactive installation - Get server IP address automatically - Pass publicip as required positional argument - Set default options (OpenLiteSpeed, Full install, Local MySQL) - Ensures install.py runs in non-interactive mode - Fixes issue where old interactive installer was being used --- cyberpanel.sh | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index c7f059a21..fbe167b83 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -932,7 +932,7 @@ except Exception as e: # install/install.py is the actual installer that we can control local installer_py="install/install.py" if [ -f "$installer_py" ]; then - print_status "Using install/install.py directly for installation" + print_status "Using install/install.py directly for installation (non-interactive mode)" # If MariaDB 10.x is installed, disable repositories right before running installer if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then @@ -942,10 +942,41 @@ except Exception as e: fi fi + # Get server IP address (required by install.py) + local server_ip + if command -v curl >/dev/null 2>&1; then + server_ip=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null || curl -s --max-time 5 https://icanhazip.com 2>/dev/null || echo "") + fi + + if [ -z "$server_ip" ]; then + # Fallback: try to get IP from network interfaces + server_ip=$(ip route get 8.8.8.8 2>/dev/null | awk '{print $7; exit}' || \ + hostname -I 2>/dev/null | awk '{print $1}' || \ + echo "127.0.0.1") + fi + + if [ -z "$server_ip" ] || [ "$server_ip" = "127.0.0.1" ]; then + print_status "WARNING: Could not detect public IP, using 127.0.0.1" + server_ip="127.0.0.1" + fi + + print_status "Detected server IP: $server_ip" + # Build installer arguments based on user preferences - local install_args=() + # install.py requires publicip as first positional argument + local install_args=("$server_ip") + + # Add optional arguments based on user preferences + # Default: OpenLiteSpeed, Full installation (postfix, powerdns, ftp), Local MySQL + # These match what the user selected in the interactive prompts + install_args+=("--postfix" "ON") + install_args+=("--powerdns" "ON") + install_args+=("--ftp" "ON") + install_args+=("--remotemysql" "OFF") + if [ "$DEBUG_MODE" = true ]; then - install_args+=("--debug") + # Note: install.py doesn't have --debug, but we can set it via environment + export DEBUG_MODE=true fi # Run the Python installer directly From 615e148467c78202d836acd3373e69885512ceb5 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:38:58 +0100 Subject: [PATCH 17/27] Patch install.py directly to exclude MariaDB-server from dnf commands - Patches install.py (not just wrapper script) to add --exclude=MariaDB-server* - Handles both shell commands and Python string commands - Ensures MariaDB exclude is applied to all installation commands - Works in conjunction with dnf.conf excludes --- cyberpanel.sh | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/cyberpanel.sh b/cyberpanel.sh index fbe167b83..126b872c6 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -934,6 +934,68 @@ except Exception as e: if [ -f "$installer_py" ]; then print_status "Using install/install.py directly for installation (non-interactive mode)" + # CRITICAL: Patch install.py to exclude MariaDB-server from dnf/yum commands + if [ -n "$MARIADB_VERSION" ] && [ "$major_ver" -lt 12 ] 2>/dev/null; then + print_status "Patching install.py to exclude MariaDB-server from installation commands..." + + # Create backup + cp "$installer_py" "${installer_py}.backup" 2>/dev/null || true + + # Patch install.py to add --exclude=MariaDB-server* to dnf/yum install commands + python3 -c " +import re +import sys + +try: + with open('$installer_py', 'r') as f: + content = f.read() + + original_content = content + + # Pattern: Add --exclude=MariaDB-server* to dnf/yum install commands that install mariadb-server + def add_exclude(match): + cmd = match.group(0) + # Check if --exclude is already present + if '--exclude=MariaDB-server' in cmd: + return cmd + # Add --exclude=MariaDB-server* after install and flags, before packages + return re.sub(r'((?:dnf|yum)\s+install\s+(?:-[^\s]+\s+)*)', r'\1--exclude=MariaDB-server* ', cmd, flags=re.IGNORECASE) + + # Find all dnf/yum install commands that mention mariadb-server + content = re.sub( + r'(?:dnf|yum)\s+install[^;]*?mariadb-server[^;]*', + add_exclude, + content, + flags=re.IGNORECASE | re.MULTILINE + ) + + # Also handle MariaDB-server (capitalized) and in Python strings + content = re.sub( + r'(\"|\')(?:dnf|yum)\s+install[^\"]*?mariadb-server[^\"]*(\"|\')', + lambda m: m.group(1) + re.sub(r'((?:dnf|yum)\s+install\s+(?:-[^\s]+\s+)*)', r'\1--exclude=MariaDB-server* ', m.group(0)[1:-1], flags=re.IGNORECASE) + m.group(2), + content, + flags=re.IGNORECASE | re.MULTILINE + ) + + # Only write if content changed + if content != original_content: + with open('$installer_py', 'w') as f: + f.write(content) + print('install.py patched successfully') + else: + print('No changes needed in install.py') + +except Exception as e: + print(f'Error patching install.py: {e}') + sys.exit(1) +" 2>/dev/null && print_status "install.py patched successfully" || { + # Fallback: Simple sed-based patching if Python fails + sed -i 's/\(dnf\|yum\) install\([^;]*\)mariadb-server/\1 install\2--exclude=MariaDB-server* mariadb-server/gi' "$installer_py" 2>/dev/null + sed -i 's/\(dnf\|yum\) install\([^;]*\)MariaDB-server/\1 install\2--exclude=MariaDB-server* MariaDB-server/gi' "$installer_py" 2>/dev/null + print_status "install.py patched (fallback method)" + } + fi + # If MariaDB 10.x is installed, disable repositories right before running installer if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then # Call the disable function one more time before installer runs From 9006b1bb6bea230594d75c28b017651cee2afdce Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:39:33 +0100 Subject: [PATCH 18/27] Add verification for install directory extraction - Verify install directory exists after extraction - Show archive contents if extraction fails - Ensures install/install.py is available for direct execution --- cyberpanel.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 126b872c6..c247800f9 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -884,13 +884,27 @@ except Exception as e: # Copy install directory to current location if [ "$installer_url" = "https://raw.githubusercontent.com/master3395/cyberpanel/stable/cyberpanel.sh" ]; then - cp -r cyberpanel-stable/install . 2>/dev/null || true - cp -r cyberpanel-stable/install.sh . 2>/dev/null || true + if [ -d "cyberpanel-stable" ]; then + cp -r cyberpanel-stable/install . 2>/dev/null || true + cp -r cyberpanel-stable/install.sh . 2>/dev/null || true + fi else - cp -r cyberpanel-v2.5.5-dev/install . 2>/dev/null || true - cp -r cyberpanel-v2.5.5-dev/install.sh . 2>/dev/null || true + if [ -d "cyberpanel-v2.5.5-dev" ]; then + cp -r cyberpanel-v2.5.5-dev/install . 2>/dev/null || true + cp -r cyberpanel-v2.5.5-dev/install.sh . 2>/dev/null || true + fi fi + # Verify install directory was copied + if [ ! -d "install" ]; then + print_status "ERROR: install directory not found after extraction" + print_status "Archive contents:" + ls -la 2>/dev/null | head -20 + return 1 + fi + + print_status "Verified install directory exists" + echo " ✓ CyberPanel installation files downloaded" echo " 🔄 Starting CyberPanel installation..." echo "" From e2931ad53e1a03510bf392cc5a87abdf9bbd16cb Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:44:17 +0100 Subject: [PATCH 19/27] Install Python MySQL dependencies before running install.py - Install MariaDB/MySQL development headers (mariadb-devel/mysql-devel) - Install mysqlclient Python package (provides MySQLdb) - Support for AlmaLinux 9/10, Rocky Linux, CentOS, RHEL, Ubuntu, Debian - Verify MySQLdb is available before running installer - Fixes ModuleNotFoundError: No module named 'MySQLdb' --- cyberpanel.sh | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/cyberpanel.sh b/cyberpanel.sh index c247800f9..2c57894a3 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -1038,6 +1038,77 @@ except Exception as e: print_status "Detected server IP: $server_ip" + # CRITICAL: Install Python MySQL dependencies before running install.py + # installCyberPanel.py requires MySQLdb (mysqlclient) which needs development headers + print_status "Installing Python MySQL dependencies..." + + # Detect OS for package installation + local os_family="" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + almalinux|rocky|centos|rhel|fedora) + os_family="rhel" + ;; + ubuntu|debian) + os_family="debian" + ;; + esac + fi + + # Install MariaDB/MySQL development headers and Python mysqlclient + if [ "$os_family" = "rhel" ]; then + # RHEL-based (AlmaLinux, Rocky, CentOS, RHEL) + print_status "Installing MariaDB development headers for RHEL-based system..." + + # Try to install mariadb-devel (works with MariaDB 10.x and 12.x) + if command -v dnf >/dev/null 2>&1; then + # For AlmaLinux 9/10 and newer + dnf install -y --allowerasing --skip-broken --nobest \ + mariadb-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ + dnf install -y --allowerasing --skip-broken --nobest \ + mysql-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ + dnf install -y --allowerasing --skip-broken --nobest \ + mariadb-connector-c-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || true + else + # For older systems with yum + yum install -y mariadb-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ + yum install -y mysql-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || true + fi + + # Install mysqlclient Python package + print_status "Installing mysqlclient Python package..." + python3 -m pip install --quiet --upgrade pip setuptools wheel 2>/dev/null || true + python3 -m pip install --quiet mysqlclient 2>/dev/null || { + # If pip install fails, try with build dependencies + print_status "Retrying mysqlclient installation with build dependencies..." + python3 -m pip install --quiet --no-cache-dir mysqlclient 2>/dev/null || true + } + + elif [ "$os_family" = "debian" ]; then + # Debian-based (Ubuntu, Debian) + print_status "Installing MariaDB development headers for Debian-based system..." + apt-get update -y 2>/dev/null || true + apt-get install -y libmariadb-dev libmariadb-dev-compat pkg-config build-essential python3-dev python3-pip 2>/dev/null || \ + apt-get install -y default-libmysqlclient-dev pkg-config build-essential python3-dev python3-pip 2>/dev/null || true + + # Install mysqlclient Python package + print_status "Installing mysqlclient Python package..." + python3 -m pip install --quiet --upgrade pip setuptools wheel 2>/dev/null || true + python3 -m pip install --quiet mysqlclient 2>/dev/null || { + print_status "Retrying mysqlclient installation with build dependencies..." + python3 -m pip install --quiet --no-cache-dir mysqlclient 2>/dev/null || true + } + fi + + # Verify MySQLdb is available + if python3 -c "import MySQLdb" 2>/dev/null; then + print_status "✓ MySQLdb module is available" + else + print_status "⚠️ WARNING: MySQLdb module not available, installation may fail" + print_status "Attempting to continue anyway..." + fi + # Build installer arguments based on user preferences # install.py requires publicip as first positional argument local install_args=("$server_ip") From cc30e8aed8b2a4ea03984cddc67391a04b98ac57 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:44:51 +0100 Subject: [PATCH 20/27] Add AlmaLinux 10 support to OS detection - Detect AlmaLinux 10 in detect_os() function - Treat AlmaLinux 10 same as AlmaLinux 9 for package installation - Update supported OS list to include AlmaLinux 10 - Ensures installer works on AlmaLinux 9.x and 10.x --- cyberpanel.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 2c57894a3..91d11b07c 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -81,7 +81,12 @@ detect_os() { fi # Detect OS - if echo $OUTPUT | grep -q "AlmaLinux 9" ; then + if echo $OUTPUT | grep -q "AlmaLinux 10" ; then + SERVER_OS="AlmaLinux10" + OS_FAMILY="rhel" + PACKAGE_MANAGER="dnf" + print_status "Detected: AlmaLinux 10" + elif echo $OUTPUT | grep -q "AlmaLinux 9" ; then SERVER_OS="AlmaLinux9" OS_FAMILY="rhel" PACKAGE_MANAGER="dnf" @@ -133,7 +138,7 @@ detect_os() { print_status "Detected: Debian GNU/Linux 11" else print_status "ERROR: Unsupported OS detected" - print_status "Supported OS: AlmaLinux 8/9, CentOS 8/9, Rocky Linux 8/9, Ubuntu 20.04/22.04, Debian 11/12" + print_status "Supported OS: AlmaLinux 8/9/10, CentOS 8/9, Rocky Linux 8/9, Ubuntu 20.04/22.04, Debian 11/12" return 1 fi @@ -477,8 +482,8 @@ install_dependencies() { echo "" echo "Step 3/4: Installing core packages..." - if [ "$SERVER_OS" = "AlmaLinux9" ] || [ "$SERVER_OS" = "CentOS9" ] || [ "$SERVER_OS" = "RockyLinux9" ]; then - # AlmaLinux 9 / CentOS 9 / Rocky Linux 9 + if [ "$SERVER_OS" = "AlmaLinux9" ] || [ "$SERVER_OS" = "AlmaLinux10" ] || [ "$SERVER_OS" = "CentOS9" ] || [ "$SERVER_OS" = "RockyLinux9" ]; then + # AlmaLinux 9/10 / CentOS 9 / Rocky Linux 9 $PACKAGE_MANAGER install -y ImageMagick gd libicu oniguruma python3 python3-pip python3-devel 2>/dev/null || true $PACKAGE_MANAGER install -y aspell 2>/dev/null || print_status "WARNING: aspell not available, skipping..." $PACKAGE_MANAGER install -y libc-client-devel 2>/dev/null || print_status "WARNING: libc-client-devel not available, skipping..." From 49df4ae9acfae962773eab65c6e2b567580d0657 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:48:28 +0100 Subject: [PATCH 21/27] Improve Python MySQL dependency installation with better error handling - Remove silent redirects to show actual errors - Add explicit success/failure messages - Show pip installation output for debugging - Better OS detection with fallback - Verify MySQLdb availability with version check - Add diagnostic output if installation fails - Ensures dependencies are installed before install.py runs --- cyberpanel.sh | 92 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 24 deletions(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 91d11b07c..1aed9039c 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -1045,6 +1045,10 @@ except Exception as e: # CRITICAL: Install Python MySQL dependencies before running install.py # installCyberPanel.py requires MySQLdb (mysqlclient) which needs development headers + echo "" + echo "===============================================================================================================" + echo "Installing Python MySQL dependencies (required for installCyberPanel.py)..." + echo "===============================================================================================================" print_status "Installing Python MySQL dependencies..." # Detect OS for package installation @@ -1054,11 +1058,20 @@ except Exception as e: case "$ID" in almalinux|rocky|centos|rhel|fedora) os_family="rhel" + print_status "Detected RHEL-based OS: $ID" ;; ubuntu|debian) os_family="debian" + print_status "Detected Debian-based OS: $ID" + ;; + *) + print_status "Unknown OS ID: $ID, defaulting to RHEL-based" + os_family="rhel" ;; esac + else + print_status "WARNING: /etc/os-release not found, defaulting to RHEL-based" + os_family="rhel" fi # Install MariaDB/MySQL development headers and Python mysqlclient @@ -1068,51 +1081,82 @@ except Exception as e: # Try to install mariadb-devel (works with MariaDB 10.x and 12.x) if command -v dnf >/dev/null 2>&1; then - # For AlmaLinux 9/10 and newer - dnf install -y --allowerasing --skip-broken --nobest \ - mariadb-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ - dnf install -y --allowerasing --skip-broken --nobest \ - mysql-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ - dnf install -y --allowerasing --skip-broken --nobest \ - mariadb-connector-c-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || true + # For AlmaLinux 9/10 and newer - show output for debugging + print_status "Attempting to install mariadb-devel..." + if dnf install -y --allowerasing --skip-broken --nobest \ + mariadb-devel pkgconfig gcc python3-devel python3-pip; then + print_status "✓ Successfully installed mariadb-devel" + elif dnf install -y --allowerasing --skip-broken --nobest \ + mysql-devel pkgconfig gcc python3-devel python3-pip; then + print_status "✓ Successfully installed mysql-devel" + elif dnf install -y --allowerasing --skip-broken --nobest \ + mariadb-connector-c-devel pkgconfig gcc python3-devel python3-pip; then + print_status "✓ Successfully installed mariadb-connector-c-devel" + else + print_status "⚠️ WARNING: Failed to install MariaDB development headers" + fi else # For older systems with yum - yum install -y mariadb-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || \ - yum install -y mysql-devel pkgconfig gcc python3-devel python3-pip 2>/dev/null || true + print_status "Using yum to install mariadb-devel..." + if yum install -y mariadb-devel pkgconfig gcc python3-devel python3-pip; then + print_status "✓ Successfully installed mariadb-devel" + elif yum install -y mysql-devel pkgconfig gcc python3-devel python3-pip; then + print_status "✓ Successfully installed mysql-devel" + else + print_status "⚠️ WARNING: Failed to install MariaDB development headers" + fi fi # Install mysqlclient Python package print_status "Installing mysqlclient Python package..." - python3 -m pip install --quiet --upgrade pip setuptools wheel 2>/dev/null || true - python3 -m pip install --quiet mysqlclient 2>/dev/null || { + python3 -m pip install --upgrade pip setuptools wheel 2>&1 | grep -v "already satisfied" || true + if python3 -m pip install mysqlclient 2>&1; then + print_status "✓ Successfully installed mysqlclient" + else # If pip install fails, try with build dependencies print_status "Retrying mysqlclient installation with build dependencies..." - python3 -m pip install --quiet --no-cache-dir mysqlclient 2>/dev/null || true - } + python3 -m pip install --no-cache-dir mysqlclient 2>&1 || { + print_status "⚠️ WARNING: Failed to install mysqlclient, trying alternative method..." + # Try installing from source + python3 -m pip install --no-binary mysqlclient mysqlclient 2>&1 || true + } + fi elif [ "$os_family" = "debian" ]; then # Debian-based (Ubuntu, Debian) print_status "Installing MariaDB development headers for Debian-based system..." - apt-get update -y 2>/dev/null || true - apt-get install -y libmariadb-dev libmariadb-dev-compat pkg-config build-essential python3-dev python3-pip 2>/dev/null || \ - apt-get install -y default-libmysqlclient-dev pkg-config build-essential python3-dev python3-pip 2>/dev/null || true + apt-get update -y + if apt-get install -y libmariadb-dev libmariadb-dev-compat pkg-config build-essential python3-dev python3-pip; then + print_status "✓ Successfully installed MariaDB development headers" + elif apt-get install -y default-libmysqlclient-dev pkg-config build-essential python3-dev python3-pip; then + print_status "✓ Successfully installed MySQL development headers" + else + print_status "⚠️ WARNING: Failed to install MariaDB/MySQL development headers" + fi # Install mysqlclient Python package print_status "Installing mysqlclient Python package..." - python3 -m pip install --quiet --upgrade pip setuptools wheel 2>/dev/null || true - python3 -m pip install --quiet mysqlclient 2>/dev/null || { + python3 -m pip install --upgrade pip setuptools wheel 2>&1 | grep -v "already satisfied" || true + if python3 -m pip install mysqlclient 2>&1; then + print_status "✓ Successfully installed mysqlclient" + else print_status "Retrying mysqlclient installation with build dependencies..." - python3 -m pip install --quiet --no-cache-dir mysqlclient 2>/dev/null || true - } + python3 -m pip install --no-cache-dir mysqlclient 2>&1 || true + fi fi # Verify MySQLdb is available - if python3 -c "import MySQLdb" 2>/dev/null; then - print_status "✓ MySQLdb module is available" + print_status "Verifying MySQLdb module availability..." + if python3 -c "import MySQLdb; print('MySQLdb version:', MySQLdb.__version__)" 2>&1; then + print_status "✓ MySQLdb module is available and working" else - print_status "⚠️ WARNING: MySQLdb module not available, installation may fail" - print_status "Attempting to continue anyway..." + print_status "⚠️ WARNING: MySQLdb module not available" + print_status "Attempting to diagnose the issue..." + python3 -c "import sys; print('Python path:', sys.path)" 2>&1 || true + python3 -m pip list | grep -i mysql || print_status "No MySQL-related packages found in pip list" + print_status "Attempting to continue anyway, but installation may fail..." fi + echo "" # Build installer arguments based on user preferences # install.py requires publicip as first positional argument From e271edd1b2c11416a5e3723ddee395502612281a Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:48:53 +0100 Subject: [PATCH 22/27] Fix mariadb-devel installation when MariaDB-server is excluded - Temporarily adjust dnf exclude to allow mariadb-devel installation - Only exclude MariaDB-server, not development packages - Ensures mariadb-devel can be installed even when server is excluded - Critical for Python mysqlclient package compilation --- cyberpanel.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cyberpanel.sh b/cyberpanel.sh index 1aed9039c..0748c7212 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -1080,9 +1080,24 @@ except Exception as e: print_status "Installing MariaDB development headers for RHEL-based system..." # Try to install mariadb-devel (works with MariaDB 10.x and 12.x) + # NOTE: We need mariadb-devel even if we excluded MariaDB-server + # The exclude only applies to MariaDB-server, not development packages if command -v dnf >/dev/null 2>&1; then # For AlmaLinux 9/10 and newer - show output for debugging - print_status "Attempting to install mariadb-devel..." + print_status "Attempting to install mariadb-devel (development headers only, not server)..." + # Temporarily remove exclude for devel packages if needed + local dnf_exclude_backup="" + if [ -f /etc/dnf/dnf.conf ] && grep -q "exclude=.*MariaDB" /etc/dnf/dnf.conf; then + # Check if exclude is too broad + if grep -q "exclude=.*MariaDB-server.*MariaDB-devel" /etc/dnf/dnf.conf || \ + grep -q "exclude=.*MariaDB\*" /etc/dnf/dnf.conf; then + print_status "Temporarily adjusting dnf exclude to allow mariadb-devel installation..." + # We only want to exclude MariaDB-server, not devel packages + sed -i 's/exclude=\(.*\)MariaDB-server\(.*\)MariaDB-devel\(.*\)/exclude=\1MariaDB-server\2\3/' /etc/dnf/dnf.conf 2>/dev/null || true + sed -i 's/exclude=\(.*\)MariaDB\*\(.*\)/exclude=\1MariaDB-server*\2/' /etc/dnf/dnf.conf 2>/dev/null || true + fi + fi + if dnf install -y --allowerasing --skip-broken --nobest \ mariadb-devel pkgconfig gcc python3-devel python3-pip; then print_status "✓ Successfully installed mariadb-devel" @@ -1094,6 +1109,7 @@ except Exception as e: print_status "✓ Successfully installed mariadb-connector-c-devel" else print_status "⚠️ WARNING: Failed to install MariaDB development headers" + print_status "This may cause MySQLdb installation to fail" fi else # For older systems with yum From a28c4287bf7421823c91680aaafddfd27081da29 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:58:06 +0100 Subject: [PATCH 23/27] Remove conflicting MariaDB-server-compat packages before installation - Remove MariaDB-server-compat* packages that conflict with MariaDB 10.11 - Fixes transaction test errors when installing MariaDB 10.11 - Removes compat packages from previous MariaDB 12.1 installation attempts - Ensures clean MariaDB 10.11 installation without conflicts - Also remove sudo from curl command (not needed when running as root) --- install/install.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/install/install.py b/install/install.py index 89a3fb783..45b3254f3 100644 --- a/install/install.py +++ b/install/install.py @@ -349,6 +349,17 @@ class preFlightsChecks: # This prevents upgrade attempts in Pre_Install_Required_Components self.disableMariaDB12RepositoryIfNeeded() + # CRITICAL: Remove conflicting MariaDB compat packages before installation + # These packages from MariaDB 12.1 can conflict with MariaDB 10.11 + self.stdOut("Removing conflicting MariaDB compat packages...", 1) + try: + # Remove MariaDB-server-compat packages that conflict with MariaDB 10.11 + compat_remove_cmd = "dnf remove -y MariaDB-server-compat* 2>/dev/null || rpm -e --nodeps MariaDB-server-compat* 2>/dev/null || true" + subprocess.run(compat_remove_cmd, shell=True, timeout=60) + self.stdOut("Removed conflicting MariaDB compat packages", 1) + except Exception as e: + self.stdOut(f"Warning: Could not remove compat packages: {e}", 0) + # Check if MariaDB is already installed before attempting installation is_installed, installed_version, major_minor = self.checkExistingMariaDB() @@ -1789,6 +1800,20 @@ module cyberpanel_ols { else: # RHEL-based MariaDB installation + # CRITICAL: Remove conflicting MariaDB compat packages first + # These packages from MariaDB 12.1 can conflict with MariaDB 10.11 + self.stdOut("Removing conflicting MariaDB compat packages...", 1) + try: + # Remove MariaDB-server-compat packages that conflict with MariaDB 10.11 + compat_remove_cmd = "dnf remove -y MariaDB-server-compat* 2>/dev/null || rpm -e --nodeps MariaDB-server-compat* 2>/dev/null || true" + result = subprocess.run(compat_remove_cmd, shell=True, timeout=60, capture_output=True) + if result.returncode == 0 or "not installed" in result.stdout.decode('utf-8', errors='ignore').lower(): + self.stdOut("Removed conflicting MariaDB compat packages", 1) + else: + self.stdOut("No conflicting compat packages found or already removed", 1) + except Exception as e: + self.stdOut(f"Warning: Could not remove compat packages: {e}", 0) + # Check if MariaDB is already installed before setting up repository is_installed, installed_version, major_minor = self.checkExistingMariaDB() @@ -1809,7 +1834,7 @@ module cyberpanel_ols { pass # Set up MariaDB 12.1 repository only if not already installed - command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1' + command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version=12.1' self.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'dnf install mariadb-server mariadb-devel mariadb-client-utils -y' From 99b24f853a6a3c30c6a5429b6fd80a110685b4af Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 22:58:56 +0100 Subject: [PATCH 24/27] Fix mysql command not found error in install_utils.call - Detect mysql/mariadb commands and find binary path automatically - Replace mysql/mariadb with full path (/usr/bin/mysql or /usr/bin/mariadb) - Use shell=True for mysql commands to handle complex SQL properly - Fixes FileNotFoundError when executing mysql commands - Works with both mysql and mariadb binaries --- install/install_utils.py | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/install/install_utils.py b/install/install_utils.py index 07982c0c0..a150e0174 100644 --- a/install/install_utils.py +++ b/install/install_utils.py @@ -556,6 +556,50 @@ def call(command, distro, bracket, message, log=0, do_exit=0, code=os.EX_OK, she os._exit(code) return False + # CRITICAL: For mysql/mariadb commands, use shell=True and find the binary path + # This fixes "No such file or directory: 'mysql'" errors + if not shell and ('mysql' in command or 'mariadb' in command): + # Try to find mysql/mariadb binary path + mysql_paths = ['/usr/bin/mysql', '/usr/bin/mariadb', '/usr/local/bin/mysql', '/usr/local/bin/mariadb'] + mysql_found = None + + # Check which mysql binary exists + for path in mysql_paths: + if os.path.exists(path): + mysql_found = path + break + + # If mysql/mariadb is in command but not found, try to use shell=True + if mysql_found is None: + # Try using 'which' to find mysql + try: + which_result = subprocess.run(['which', 'mysql'], capture_output=True, text=True, timeout=5) + if which_result.returncode == 0: + mysql_found = which_result.stdout.strip() + except: + pass + + # If still not found, try mariadb + if mysql_found is None: + try: + which_result = subprocess.run(['which', 'mariadb'], capture_output=True, text=True, timeout=5) + if which_result.returncode == 0: + mysql_found = which_result.stdout.strip() + except: + pass + + # If mysql/mariadb command found, replace it with full path + if mysql_found: + # Replace 'mysql' or 'mariadb' at the start of command with full path + import re + command = re.sub(r'^(mysql|mariadb)\s', f'{mysql_found} ', command) + # Also replace if it's in the middle (e.g., "sudo mysql") + command = re.sub(r'\s(mysql|mariadb)\s', f' {mysql_found} ', command) + command = re.sub(r'\s(mysql|mariadb)$', f' {mysql_found}', command) + + # Use shell=True for mysql commands to handle complex SQL properly + shell = True + finalMessage = 'Running: %s' % (message) stdOut(finalMessage, log) count = 0 From de21c03fc7285bf8e26e5a49fac3d8e2aaf075e4 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 26 Jan 2026 23:21:53 +0100 Subject: [PATCH 25/27] Fix MariaDB compat, mysql path, and OpenLiteSpeed binary install MariaDB-server-compat: - Remove MariaDB-server-compat* in main() before any MariaDB install - Use dnf remove then rpm -e --nodeps loop in main(), installMySQL, fix_almalinux9 - Prevents transaction conflicts when installing MariaDB 10.11 mysql command not found: - install_utils.call: detect mysql/mariadb commands, use shell=True and full path - Replace leading mysql/mariadb with /usr/bin/mariadb or /usr/bin/mysql - Fixes FileNotFoundError when changeMYSQLRootPassword runs OpenLiteSpeed: - Create /usr/local/lsws and /usr/local/lsws/bin before installing custom binary - Fixes 'No such file or directory: /usr/local/lsws/bin/openlitespeed' --- install/install.py | 47 +++++++++++++++++++++++++-------- install/install_utils.py | 56 +++++++++------------------------------- 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/install/install.py b/install/install.py index 45b3254f3..3df2263bc 100644 --- a/install/install.py +++ b/install/install.py @@ -354,11 +354,15 @@ class preFlightsChecks: self.stdOut("Removing conflicting MariaDB compat packages...", 1) try: # Remove MariaDB-server-compat packages that conflict with MariaDB 10.11 - compat_remove_cmd = "dnf remove -y MariaDB-server-compat* 2>/dev/null || rpm -e --nodeps MariaDB-server-compat* 2>/dev/null || true" - subprocess.run(compat_remove_cmd, shell=True, timeout=60) + subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) + r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) + for line in (r.stdout or "").strip().splitlines(): + pkg = (line.strip().split() or [""])[0] + if pkg and "MariaDB-server-compat" in pkg: + subprocess.run(["rpm", "-e", "--nodeps", pkg], timeout=30) self.stdOut("Removed conflicting MariaDB compat packages", 1) except Exception as e: - self.stdOut(f"Warning: Could not remove compat packages: {e}", 0) + self.stdOut("Warning: Could not remove compat packages: " + str(e), 0) # Check if MariaDB is already installed before attempting installation is_installed, installed_version, major_minor = self.checkExistingMariaDB() @@ -1261,6 +1265,13 @@ class preFlightsChecks: self.stdOut("Installing custom binaries...", 1) try: + # Ensure /usr/local/lsws/bin exists (dnf openlitespeed may use different layout) + ols_bin_dir = os.path.dirname(OLS_BINARY_PATH) + os.makedirs(ols_bin_dir, mode=0o755, exist_ok=True) + ols_base = os.path.dirname(ols_bin_dir) + if not os.path.isdir(ols_base): + os.makedirs(ols_base, mode=0o755, exist_ok=True) + # Make binary executable before moving os.chmod(tmp_binary, 0o755) @@ -1804,15 +1815,15 @@ module cyberpanel_ols { # These packages from MariaDB 12.1 can conflict with MariaDB 10.11 self.stdOut("Removing conflicting MariaDB compat packages...", 1) try: - # Remove MariaDB-server-compat packages that conflict with MariaDB 10.11 - compat_remove_cmd = "dnf remove -y MariaDB-server-compat* 2>/dev/null || rpm -e --nodeps MariaDB-server-compat* 2>/dev/null || true" - result = subprocess.run(compat_remove_cmd, shell=True, timeout=60, capture_output=True) - if result.returncode == 0 or "not installed" in result.stdout.decode('utf-8', errors='ignore').lower(): - self.stdOut("Removed conflicting MariaDB compat packages", 1) - else: - self.stdOut("No conflicting compat packages found or already removed", 1) + subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) + r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) + for line in (r.stdout or "").strip().splitlines(): + pkg = (line.strip().split() or [""])[0] + if pkg and "MariaDB-server-compat" in pkg: + subprocess.run(["rpm", "-e", "--nodeps", pkg], timeout=30) + self.stdOut("Removed conflicting MariaDB compat packages", 1) except Exception as e: - self.stdOut(f"Warning: Could not remove compat packages: {e}", 0) + self.stdOut("Warning: Could not remove compat packages: " + str(e), 0) # Check if MariaDB is already installed before setting up repository is_installed, installed_version, major_minor = self.checkExistingMariaDB() @@ -6426,6 +6437,20 @@ def main(): # This must run before Pre_Install_Required_Components tries to install MariaDB checks.disableMariaDB12RepositoryIfNeeded() + # CRITICAL: Remove MariaDB-server-compat* before ANY MariaDB installation + # This package conflicts with MariaDB 10.11 and must be removed early + preFlightsChecks.stdOut("Removing conflicting MariaDB-server-compat packages...", 1) + try: + subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) + r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) + for line in (r.stdout or "").strip().splitlines(): + pkg = (line.strip().split() or [""])[0] + if pkg and "MariaDB-server-compat" in pkg: + subprocess.run(["rpm", "-e", "--nodeps", pkg], timeout=30) + preFlightsChecks.stdOut("MariaDB compat cleanup completed", 1) + except Exception as e: + preFlightsChecks.stdOut("Warning: compat cleanup: " + str(e), 0) + # Ensure MySQL password file is created early to prevent FileNotFoundError checks.ensure_mysql_password_file() diff --git a/install/install_utils.py b/install/install_utils.py index a150e0174..5976ad0e4 100644 --- a/install/install_utils.py +++ b/install/install_utils.py @@ -556,58 +556,26 @@ def call(command, distro, bracket, message, log=0, do_exit=0, code=os.EX_OK, she os._exit(code) return False - # CRITICAL: For mysql/mariadb commands, use shell=True and find the binary path - # This fixes "No such file or directory: 'mysql'" errors + # CRITICAL: For mysql/mariadb commands, always use shell=True and full binary path + # This fixes "No such file or directory: 'mysql'" when run via shlex.split if not shell and ('mysql' in command or 'mariadb' in command): - # Try to find mysql/mariadb binary path - mysql_paths = ['/usr/bin/mysql', '/usr/bin/mariadb', '/usr/local/bin/mysql', '/usr/local/bin/mariadb'] - mysql_found = None - - # Check which mysql binary exists - for path in mysql_paths: - if os.path.exists(path): - mysql_found = path - break - - # If mysql/mariadb is in command but not found, try to use shell=True - if mysql_found is None: - # Try using 'which' to find mysql - try: - which_result = subprocess.run(['which', 'mysql'], capture_output=True, text=True, timeout=5) - if which_result.returncode == 0: - mysql_found = which_result.stdout.strip() - except: - pass - - # If still not found, try mariadb - if mysql_found is None: - try: - which_result = subprocess.run(['which', 'mariadb'], capture_output=True, text=True, timeout=5) - if which_result.returncode == 0: - mysql_found = which_result.stdout.strip() - except: - pass - - # If mysql/mariadb command found, replace it with full path - if mysql_found: - # Replace 'mysql' or 'mariadb' at the start of command with full path - import re - command = re.sub(r'^(mysql|mariadb)\s', f'{mysql_found} ', command) - # Also replace if it's in the middle (e.g., "sudo mysql") - command = re.sub(r'\s(mysql|mariadb)\s', f' {mysql_found} ', command) - command = re.sub(r'\s(mysql|mariadb)$', f' {mysql_found}', command) - - # Use shell=True for mysql commands to handle complex SQL properly + import re + mysql_bin = '/usr/bin/mariadb' if os.path.exists('/usr/bin/mariadb') else '/usr/bin/mysql' + if not os.path.exists(mysql_bin): + mysql_bin = '/usr/bin/mysql' + # Replace only leading "mysql" or "mariadb" (executable), not "mysql" in SQL like "use mysql;" + if re.match(r'^\s*(sudo\s+)?(mysql|mariadb)\s', command): + command = re.sub(r'^(\s*)(?:sudo\s+)?(mysql|mariadb)(\s)', r'\g<1>' + mysql_bin + r'\g<3>', command, count=1) shell = True finalMessage = 'Running: %s' % (message) stdOut(finalMessage, log) count = 0 while True: - if shell == False: - res = subprocess.call(shlex.split(command)) - else: + if shell: res = subprocess.call(command, shell=True) + else: + res = subprocess.call(shlex.split(command)) if resFailed(distro, res): count = count + 1 From da4c1d9601b6a80fa5e18c14c55dcf6949e42c50 Mon Sep 17 00:00:00 2001 From: master3395 Date: Tue, 27 Jan 2026 00:23:56 +0100 Subject: [PATCH 26/27] Fix compat removal, shell metachars in call(), upgrade AlmaLinux 9 MariaDB - install_utils.call: use shell=True for commands with ||, 2>, |, etc. Avoids 'No matching repo to modify: 2>/dev/null, true, ||' when dnf config-manager '... 2>/dev/null || true' is run via shlex.split. - Add explicit 'rpm -e --nodeps MariaDB-server-compat-12.1.2-1.el9.noarch' before dnf remove in main(), installMySQL, fix_almalinux9_comprehensive. - upgrade fix_almalinux9_mariadb: add compat removal before MariaDB install; use MariaDB 10.11 repo instead of 12.1 to avoid compat conflicts. --- install/install.py | 4 +++- install/install_utils.py | 5 +++++ plogical/upgrade.py | 17 +++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/install/install.py b/install/install.py index 3df2263bc..384aeb76f 100644 --- a/install/install.py +++ b/install/install.py @@ -353,7 +353,7 @@ class preFlightsChecks: # These packages from MariaDB 12.1 can conflict with MariaDB 10.11 self.stdOut("Removing conflicting MariaDB compat packages...", 1) try: - # Remove MariaDB-server-compat packages that conflict with MariaDB 10.11 + subprocess.run("rpm -e --nodeps MariaDB-server-compat-12.1.2-1.el9.noarch 2>/dev/null; true", shell=True, timeout=30) subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) for line in (r.stdout or "").strip().splitlines(): @@ -1815,6 +1815,7 @@ module cyberpanel_ols { # These packages from MariaDB 12.1 can conflict with MariaDB 10.11 self.stdOut("Removing conflicting MariaDB compat packages...", 1) try: + subprocess.run("rpm -e --nodeps MariaDB-server-compat-12.1.2-1.el9.noarch 2>/dev/null; true", shell=True, timeout=30) subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) for line in (r.stdout or "").strip().splitlines(): @@ -6441,6 +6442,7 @@ def main(): # This package conflicts with MariaDB 10.11 and must be removed early preFlightsChecks.stdOut("Removing conflicting MariaDB-server-compat packages...", 1) try: + subprocess.run("rpm -e --nodeps MariaDB-server-compat-12.1.2-1.el9.noarch 2>/dev/null; true", shell=True, timeout=30) subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) for line in (r.stdout or "").strip().splitlines(): diff --git a/install/install_utils.py b/install/install_utils.py index 5976ad0e4..5549550fc 100644 --- a/install/install_utils.py +++ b/install/install_utils.py @@ -556,6 +556,11 @@ def call(command, distro, bracket, message, log=0, do_exit=0, code=os.EX_OK, she os._exit(code) return False + # CRITICAL: Use shell=True for commands with shell metacharacters + # Avoids "No matching repo to modify: 2>/dev/null, true, ||" when shlex.split splits them + if not shell and any(x in command for x in (' || ', ' 2>/dev', ' 2>', ' | ', '; true', '|| true')): + shell = True + # CRITICAL: For mysql/mariadb commands, always use shell=True and full binary path # This fixes "No such file or directory: 'mysql'" when run via shlex.split if not shell and ('mysql' in command or 'mariadb' in command): diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 5052e0c48..9a1ff2353 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -4299,6 +4299,19 @@ echo $oConfig->Save() ? 'Done' : 'Error'; Upgrade.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1) try: + # CRITICAL: Remove MariaDB-server-compat* before any MariaDB install (conflicts with 10.11) + Upgrade.stdOut("Removing conflicting MariaDB-server-compat packages...", 1) + try: + subprocess.run("rpm -e --nodeps MariaDB-server-compat-12.1.2-1.el9.noarch 2>/dev/null; true", shell=True, timeout=30) + subprocess.run("dnf remove -y 'MariaDB-server-compat*' 2>/dev/null || true", shell=True, timeout=60) + r = subprocess.run("rpm -qa 2>/dev/null | grep -i MariaDB-server-compat", shell=True, capture_output=True, text=True, timeout=30) + for line in (r.stdout or "").strip().splitlines(): + pkg = (line.strip().split() or [""])[0] + if pkg and "MariaDB-server-compat" in pkg: + subprocess.run(["rpm", "-e", "--nodeps", pkg], timeout=30) + except Exception as e: + Upgrade.stdOut("Warning: compat cleanup: " + str(e), 0) + # Disable problematic MariaDB MaxScale repository Upgrade.stdOut("Disabling problematic MariaDB MaxScale repository...", 1) command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true" @@ -4320,9 +4333,9 @@ echo $oConfig->Save() ? 'Done' : 'Error'; command = "dnf clean all" subprocess.run(command, shell=True, capture_output=True) - # Install MariaDB from official repository + # Install MariaDB 10.11 from official repository (avoid 12.1 compat conflicts) Upgrade.stdOut("Setting up official MariaDB repository...", 1) - command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='12.1'" + command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'" result = subprocess.run(command, shell=True, capture_output=True, text=True) if result.returncode != 0: Upgrade.stdOut(f"Warning: MariaDB repo setup failed: {result.stderr}", 0) From 2bde2624f0f454ba39c1b9c4ef2932a7dc5225bb Mon Sep 17 00:00:00 2001 From: master3395 Date: Tue, 27 Jan 2026 00:32:45 +0100 Subject: [PATCH 27/27] Enhance plugin store: Add upgrade button, auto-backup, revert functionality, cache randomization, and local time display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add upgrade button in plugin store when updates are available - Implement automatic plugin backup before upgrades - Add revert version functionality with backup selection - Randomize cache duration (±10 minutes) to prevent simultaneous GitHub API requests - Display cache expiry time in user's local timezone and locale format - Fix revert plugin function to work without event object - Improve error handling in plugin store operations --- .../templates/pluginHolder/plugins.html | 371 ++++++++++++- pluginHolder/urls.py | 3 + pluginHolder/views.py | 522 +++++++++++++++++- 3 files changed, 879 insertions(+), 17 deletions(-) diff --git a/pluginHolder/templates/pluginHolder/plugins.html b/pluginHolder/templates/pluginHolder/plugins.html index 089569bc6..f53e351a0 100644 --- a/pluginHolder/templates/pluginHolder/plugins.html +++ b/pluginHolder/templates/pluginHolder/plugins.html @@ -709,6 +709,32 @@ cursor: not-allowed; } + .btn-upgrade { + padding: 8px 16px; + background: #f59e0b; + color: white; + border: none; + border-radius: 6px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s; + display: inline-flex; + align-items: center; + gap: 6px; + } + + .btn-upgrade:hover:not(:disabled) { + background: #d97706; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(245,158,11,0.3); + } + + .btn-upgrade:disabled { + opacity: 0.6; + cursor: not-allowed; + } + .btn-link { padding: 6px 12px; background: var(--bg-secondary, #f8f9ff); @@ -772,6 +798,17 @@ box-shadow: 0 4px 8px rgba(88,86,214,0.3); } + .btn-revert { + background: #6c757d; + color: white; + } + + .btn-revert:hover:not(:disabled) { + background: #5a6268; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(108,117,125,0.3); + } + .btn-uninstall { background: #dc3545; color: white; @@ -1042,6 +1079,9 @@ {% trans "Activate" %} {% endif %} + @@ -1123,6 +1163,9 @@ {% trans "Activate" %} {% endif %} + @@ -1194,6 +1237,17 @@
+ +
+ {% trans "Loading plugins from store..." %} +
+ + + +
@@ -1208,6 +1262,9 @@ {% trans "Cache Information:" %} {% trans "Plugin store data is cached for 1 hour to improve performance and reduce GitHub API rate limits. New plugins may take up to 1 hour to appear after being published." %} + {% if cache_expiry_timestamp %} +
{% trans "Next cache update:" %} {% trans "Calculating..." %} + {% endif %}

@@ -1410,12 +1467,20 @@ function displayStorePlugins() {

`; - // Action column - Store view only shows Install/Installed (no Deactivate/Uninstall) + // Action column - Store view only shows Install/Installed/Upgrade (no Deactivate/Uninstall) // NOTE: Store view should NOT show Deactivate/Uninstall buttons - users manage from Grid/Table views let actionHtml = ''; if (plugin.installed) { - // Show "Installed" text - actionHtml = 'Installed'; + // Check if update is available + if (plugin.update_available) { + // Show Upgrade button + actionHtml = ``; + } else { + // Show "Installed" text + actionHtml = 'Installed'; + } } else { // Show Install button actionHtml = `