From 4c76ddc2a30d747b60eacd56652ce2af3c0805a1 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Mon, 2 Mar 2026 21:50:25 +1300 Subject: [PATCH] (fix): Fix installer Swoole migration and database selection --- app/views/install/compose.phtml | 2 +- app/views/install/installer.phtml | 15 -------------- .../Installer/Http/Installer/View.php | 20 +++++++++++++++++++ src/Appwrite/Platform/Installer/Server.php | 5 ----- src/Appwrite/Platform/Tasks/Install.php | 15 +++++++++++--- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 7664155718..1439d80124 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -13,7 +13,7 @@ $organization = $this->getParam('organization', ''); $image = $this->getParam('image', ''); $enableAssistant = $this->getParam('enableAssistant', false); $dbService = $this->getParam('database', 'mongodb'); -$allowedDbServices = ['mariadb', 'mongodb']; +$allowedDbServices = ['mariadb', 'mongodb', 'postgresql']; if (!\in_array($dbService, $allowedDbServices, true)) { $dbService = 'mongodb'; } diff --git a/app/views/install/installer.phtml b/app/views/install/installer.phtml index 9d5a3a0d39..5aef2efa77 100644 --- a/app/views/install/installer.phtml +++ b/app/views/install/installer.phtml @@ -13,21 +13,6 @@ $defaultDatabase = $vars['_APP_DB_ADAPTER']['default'] ?? 'mongodb'; $lockedDatabase = $isUpgrade && empty($lockedDatabase) ? $defaultDatabase : $lockedDatabase; $isLocalInstall = $isLocalInstall ?? false; -$step = isset($_GET['step']) ? (int) $_GET['step'] : 1; -$step = max(1, min(5, $step)); -if ($isUpgrade && ($step === 2 || $step === 3)) { - $step = 4; -} - -$partialFile = __DIR__ . "/installer/templates/steps/step-{$step}.phtml"; -if (!is_file($partialFile)) { - $partialFile = __DIR__ . "/installer/templates/steps/step-1.phtml"; -} - -if (isset($_GET['partial'])) { - include $partialFile; - exit; -} $cardStep = min(4, $step); $stepFile = __DIR__ . "/installer/templates/steps/step-{$cardStep}.phtml"; diff --git a/src/Appwrite/Platform/Installer/Http/Installer/View.php b/src/Appwrite/Platform/Installer/Http/Installer/View.php index 7d7ecfbed6..170b298a96 100644 --- a/src/Appwrite/Platform/Installer/Http/Installer/View.php +++ b/src/Appwrite/Platform/Installer/Http/Installer/View.php @@ -34,6 +34,7 @@ class View extends Action $response->addHeader('Content-Security-Policy', implode('; ', Server::INSTALLER_CSP)); + $params = $request->getParams(); $vars = $config->getVars(); $defaultHttpPort = $config->getDefaultHttpPort(); $defaultHttpsPort = $config->getDefaultHttpsPort(); @@ -46,6 +47,25 @@ class View extends Action $defaultEmailCertificates = 'walterobrien@example.com'; } + $step = isset($params['step']) ? (int) $params['step'] : 1; + $step = max(1, min(5, $step)); + if ($isUpgrade && ($step === 2 || $step === 3)) { + $step = 4; + } + + $partialFile = $paths['views'] . "/installer/templates/steps/step-{$step}.phtml"; + if (!is_file($partialFile)) { + $partialFile = $paths['views'] . '/installer/templates/steps/step-1.phtml'; + } + + if (isset($params['partial'])) { + ob_start(); + include $partialFile; + $html = ob_get_clean(); + $response->html($html); + return; + } + ob_start(); include $paths['views'] . '/installer.phtml'; $html = ob_get_clean(); diff --git a/src/Appwrite/Platform/Installer/Server.php b/src/Appwrite/Platform/Installer/Server.php index cbda61114c..6627afac4f 100644 --- a/src/Appwrite/Platform/Installer/Server.php +++ b/src/Appwrite/Platform/Installer/Server.php @@ -207,11 +207,6 @@ class Server $app->run($request, $response); }); - // Handle Ctrl+C gracefully - \Swoole\Process::signal(2, function () use ($server) { - $server->shutdown(); - }); - $server->start(); } diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index ed0d7cbe4a..76f527a3ef 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -14,6 +14,7 @@ use Utopia\Fetch\Client; use Utopia\Platform\Action; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; class Install extends Action { @@ -51,7 +52,7 @@ class Install extends Action ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) - ->param('database', 'mongodb', new Text(0), 'Database to use (mongodb|mariadb|postgres)', true) + ->param('database', 'mongodb', new WhiteList(['mongodb', 'mariadb', 'postgresql']), 'Database to use (mongodb|mariadb|postgresql)', true) ->callback($this->action(...)); } @@ -308,9 +309,12 @@ class Install extends Action ]); // Start Swoole-based installer server in background + // Redirect stdout/stderr to a log file so exec() returns immediately + // (otherwise the backgrounded process holds the pipe open and exec() hangs) $serverScript = \escapeshellarg(dirname(__DIR__) . '/Installer/Server.php'); + $logFile = \sys_get_temp_dir() . '/appwrite-installer-server.log'; $output = []; - \exec("php {$serverScript} 2>&1 & echo $!", $output); + \exec("php {$serverScript} > " . \escapeshellarg($logFile) . " 2>&1 & echo \$!", $output); $pid = isset($output[0]) ? (int) $output[0] : 0; \register_shutdown_function(function () use ($pid) { @@ -318,9 +322,14 @@ class Install extends Action @\posix_kill($pid, SIGTERM); } }); - \sleep(3); + \sleep(1); if (!$this->waitForWebServer($port)) { + $log = @\file_get_contents($logFile); + if ($log !== false && $log !== '') { + Console::error('Installer server log:'); + Console::error($log); + } Console::warning('Web installer did not respond in time. Please refresh the browser.'); return; }