From b3fad9ee6ceb8697eaf853a5aff3ed39b8c9136a Mon Sep 17 00:00:00 2001 From: Babak Alizadeh Date: Sun, 27 Apr 2025 15:16:30 +0000 Subject: [PATCH] update auto updater --- .../src/Command/UpdateSoftwareCommand.php | 217 ++++++++++-------- 1 file changed, 124 insertions(+), 93 deletions(-) diff --git a/hesabixCore/src/Command/UpdateSoftwareCommand.php b/hesabixCore/src/Command/UpdateSoftwareCommand.php index f2b4a51..693deb0 100644 --- a/hesabixCore/src/Command/UpdateSoftwareCommand.php +++ b/hesabixCore/src/Command/UpdateSoftwareCommand.php @@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; #[AsCommand( name: 'hesabix:update', - description: 'Updates the software by pulling from GitHub, clearing cache, updating the database, and building the frontend.' + description: 'نرم‌افزار را با دریافت تغییرات از GitHub، پاک کردن کش، به‌روزرسانی دیتابیس و ساخت فرانت‌اند به‌روز می‌کند.' )] class UpdateSoftwareCommand extends Command { @@ -40,24 +40,24 @@ class UpdateSoftwareCommand extends Command $this->rootDir = dirname($this->appDir); $this->archiveDir = $this->rootDir . '/hesabixArchive'; $this->backupDir = $this->rootDir . '/hesabixBackup'; - $this->webUIDir = $this->rootDir . '/webUI'; // مسیر پوشه فرانت‌اند + $this->webUIDir = $this->rootDir . '/webUI'; $envConfig = file_exists($this->appDir . '/.env.local.php') ? require $this->appDir . '/.env.local.php' : []; $this->env = $envConfig['APP_ENV'] ?? getenv('APP_ENV') ?: 'prod'; - $this->logger->info("Environment detected: " . $this->env); + $this->logger->info("محیط شناسایی شد: " . $this->env); parent::__construct(); } protected function configure(): void { - $this->addArgument('state-file', InputArgument::OPTIONAL, 'Path to the state file'); + $this->addArgument('state-file', InputArgument::OPTIONAL, 'مسیر فایل وضعیت'); } protected function execute(InputInterface $input, OutputInterface $output): int { $lock = $this->lockFactory->createLock('hesabix-update', 3600); if (!$lock->acquire()) { - $this->writeOutput($output, 'Another update process is currently running. Please try again later.'); - $this->logger->warning('Update attempt blocked due to existing lock.'); + $this->writeOutput($output, 'یک فرآیند به‌روزرسانی دیگر در حال اجراست. لطفاً بعداً تلاش کنید.'); + $this->logger->warning('تلاش برای به‌روزرسانی به دلیل قفل موجود متوقف شد.'); return Command::FAILURE; } @@ -76,18 +76,18 @@ class UpdateSoftwareCommand extends Command $uuid = json_decode(file_get_contents($this->stateFile), true)['uuid']; - $this->logger->info("Starting software update with UUID: $uuid in {$this->env} mode"); - $this->writeOutput($output, "Starting software update (UUID: $uuid) in {$this->env} mode"); + $this->logger->info("شروع به‌روزرسانی نرم‌افزار با UUID: $uuid در حالت {$this->env}"); + $this->writeOutput($output, "شروع به‌روزرسانی نرم‌افزار (UUID: $uuid) در حالت {$this->env}"); $state = $this->loadState($uuid); $state['log'] = $state['log'] ?? ''; if ($this->isUpToDate()) { - $this->writeOutput($output, 'The software is already up to date with the remote repository.'); - $this->logger->info('No update needed, software is up to date.'); - $state['log'] .= "No update needed, software is up to date.\n"; + $this->writeOutput($output, 'نرم‌افزار از قبل با مخزن ریموت به‌روز است.'); + $this->logger->info('به‌روزرسانی لازم نیست، نرم‌افزار به‌روز است.'); + $state['log'] .= "به‌روزرسانی لازم نیست، نرم‌افزار به‌روز است.\n"; $state['completedSteps'] = ['post_update_test']; - $this->saveState($uuid, $state, $output, 'No update needed'); + $this->saveState($uuid, $state, $output, 'به‌روزرسانی لازم نیست'); $lock->release(); return Command::SUCCESS; } @@ -103,11 +103,11 @@ class UpdateSoftwareCommand extends Command if (!in_array('pre_checks', $state['completedSteps'])) { $this->preUpdateChecks($output); $state['completedSteps'][] = 'pre_checks'; - $this->saveState($uuid, $state, $output, 'Pre-update checks completed'); + $this->saveState($uuid, $state, $output, 'بررسی‌های پیش از به‌روزرسانی تکمیل شد'); } if (!in_array('archive_backup', $state['completedSteps'])) { - $this->writeOutput($output, 'Backing up hesabixArchive...'); + $this->writeOutput($output, 'در حال بکاپ‌گیری از hesabixArchive...'); $archiveBackupDir = $this->backupDir . '/' . Uuid::uuid4(); if (!is_dir($archiveBackupDir)) { mkdir($archiveBackupDir, 0755, true); @@ -118,52 +118,49 @@ class UpdateSoftwareCommand extends Command $archiveHashBefore = $this->getDirectoryHash($this->archiveDir); $state['archiveHashBefore'] = $archiveHashBefore; $state['completedSteps'][] = 'archive_backup'; - $this->saveState($uuid, $state, $output, 'hesabixArchive backed up'); + $this->saveState($uuid, $state, $output, 'بکاپ hesabixArchive انجام شد'); } else { $archiveBackup = $state['archiveBackup']; $archiveHashBefore = $state['archiveHashBefore']; } if (!in_array('git_pull', $state['completedSteps'])) { - $this->writeOutput($output, 'Setting up tracking for master branch...'); + $this->writeOutput($output, 'تنظیم ردیابی برای شاخه master...'); $this->runProcess(['git', 'branch', '--set-upstream-to=origin/master', 'master'], $this->rootDir, $output, 1); - - $this->writeOutput($output, 'Pulling latest changes from GitHub...'); + $this->writeOutput($output, 'دریافت آخرین تغییرات از GitHub...'); $gitHeadBefore = $this->getCurrentGitHead(); $this->runProcess(['git', 'pull'], $this->rootDir, $output, 3); $state['gitHeadBefore'] = $gitHeadBefore; $state['completedSteps'][] = 'git_pull'; - $this->saveState($uuid, $state, $output, 'Git pull completed'); + $this->saveState($uuid, $state, $output, 'دریافت تغییرات Git تکمیل شد'); } else { $gitHeadBefore = $state['gitHeadBefore']; } if (!in_array('composer_install', $state['completedSteps'])) { - $this->writeOutput($output, 'Installing dependencies...'); + $this->writeOutput($output, 'نصب وابستگی‌ها...'); $composerCommand = ['composer', 'install', '--optimize-autoloader']; if ($this->env !== 'dev') { $composerCommand[] = '--no-dev'; - $composerCommand[] = '--no-scripts'; } - $this->runProcess($composerCommand, $this->appDir, $output, 3); + $this->runProcess($composerCommand, $this->appDir, $output, 3, true); $state['completedSteps'][] = 'composer_install'; - $this->saveState($uuid, $state, $output, 'Dependencies installed'); + $this->saveState($uuid, $state, $output, 'وابستگی‌ها نصب شدند'); } if (!in_array('composer_install_core', $state['completedSteps'])) { - $this->writeOutput($output, 'Installing dependencies in hesabixCore...'); + $this->writeOutput($output, 'نصب وابستگی‌ها در hesabixCore...'); $composerCommand = ['composer', 'install', '--optimize-autoloader']; if ($this->env !== 'dev') { $composerCommand[] = '--no-dev'; - $composerCommand[] = '--no-scripts'; } - $this->runProcess($composerCommand, $this->rootDir . '/hesabixCore', $output, 3); + $this->runProcess($composerCommand, $this->rootDir . '/hesabixCore', $output, 3, true); $state['completedSteps'][] = 'composer_install_core'; - $this->saveState($uuid, $state, $output, 'Dependencies installed in hesabixCore'); + $this->saveState($uuid, $state, $output, 'وابستگی‌ها در hesabixCore نصب شدند'); } if (!in_array('cache_clear', $state['completedSteps'])) { - $this->writeOutput($output, 'Clearing cache...'); + $this->writeOutput($output, 'پاک کردن کش...'); $cacheBackupDir = $this->backupDir . '/' . Uuid::uuid4(); if (!is_dir($cacheBackupDir)) { mkdir($cacheBackupDir, 0755, true); @@ -173,13 +170,13 @@ class UpdateSoftwareCommand extends Command $state['cacheBackup'] = $cacheBackup; $this->runProcess(['php', 'bin/console', 'cache:clear', "--env={$this->env}"], $this->appDir, $output, 3); $state['completedSteps'][] = 'cache_clear'; - $this->saveState($uuid, $state, $output, 'Cache cleared'); + $this->saveState($uuid, $state, $output, 'کش پاک شد'); } else { $cacheBackup = $state['cacheBackup']; } if (!in_array('db_update', $state['completedSteps'])) { - $this->writeOutput($output, 'Updating database schema...'); + $this->writeOutput($output, 'به‌روزرسانی طرح دیتابیس...'); $dbBackupDir = $this->backupDir . '/' . Uuid::uuid4(); if (!is_dir($dbBackupDir)) { mkdir($dbBackupDir, 0755, true); @@ -189,7 +186,7 @@ class UpdateSoftwareCommand extends Command $state['dbBackup'] = $dbBackup; $this->runProcess(['php', 'bin/console', 'doctrine:schema:update', '--force', '--no-interaction'], $this->appDir, $output, 3); $state['completedSteps'][] = 'db_update'; - $this->saveState($uuid, $state, $output, 'Database schema updated'); + $this->saveState($uuid, $state, $output, 'طرح دیتابیس به‌روز شد'); } else { $dbBackup = $state['dbBackup']; } @@ -197,58 +194,68 @@ class UpdateSoftwareCommand extends Command if (!in_array('archive_check', $state['completedSteps'])) { $archiveHashAfter = $this->getDirectoryHash($this->archiveDir); if ($archiveHashBefore !== $archiveHashAfter) { - $this->writeOutput($output, 'hesabixArchive has changed, restoring from backup...'); + $this->writeOutput($output, 'آرشیو hesabix تغییر کرده، بازگردانی از بکاپ...'); $this->restoreArchive($archiveBackup); - $this->writeOutput($output, 'hesabixArchive restored successfully.'); + $this->writeOutput($output, 'آرشیو hesabix با موفقیت بازگردانی شد.'); } else { - $this->writeOutput($output, 'hesabixArchive unchanged, no restore needed.'); + $this->writeOutput($output, 'آرشیو hesabix بدون تغییر، نیازی به بازگردانی نیست.'); } $state['completedSteps'][] = 'archive_check'; - $this->saveState($uuid, $state, $output, 'Archive check completed'); + $this->saveState($uuid, $state, $output, 'بررسی آرشیو تکمیل شد'); } - // اضافه کردن نصب پکیج‌های npm وビルド فرانت‌اند if (!in_array('npm_install', $state['completedSteps'])) { - $this->writeOutput($output, 'Installing npm packages in webUI...'); + if (!is_dir($this->webUIDir)) { + throw new \RuntimeException('پوشه فرانت‌اند webUI در مسیر وجود ندارد: ' . $this->webUIDir); + } + $this->writeOutput($output, 'نصب پکیج‌های npm در webUI...'); $this->runProcess(['npm', 'install'], $this->webUIDir, $output, 3); $state['completedSteps'][] = 'npm_install'; - $this->saveState($uuid, $state, $output, 'npm packages installed in webUI'); + $this->saveState($uuid, $state, $output, 'پکیج‌های npm در webUI نصب شدند'); } if (!in_array('npm_build', $state['completedSteps'])) { - $this->writeOutput($output, 'Building frontend in webUI...'); - $this->runProcess(['npm', 'run', 'build-only'], $this->webUIDir, $output, 3); + $this->writeOutput($output, 'ساخت فرانت‌اند در webUI...'); + $this->runProcess(['npm', 'run', 'build'], $this->webUIDir, $output, 3); $state['completedSteps'][] = 'npm_build'; - $this->saveState($uuid, $state, $output, 'Frontend built in webUI'); + $this->saveState($uuid, $state, $output, 'فرانت‌اند در webUI ساخته شد'); } if (!in_array('post_update_test', $state['completedSteps'])) { - $this->writeOutput($output, 'Running post-update tests...'); + $this->writeOutput($output, 'اجرای تست‌های پس از به‌روزرسانی...'); $this->postUpdateChecks($output); $state['completedSteps'][] = 'post_update_test'; - $this->saveState($uuid, $state, $output, 'Post-update tests completed'); + $this->saveState($uuid, $state, $output, 'تست‌های پس از به‌روزرسانی تکمیل شد'); } $commitHash = $this->getCurrentVersion(); - $this->writeOutput($output, "Software updated to commit: $commitHash"); + $this->writeOutput($output, "نرم‌افزار به کمیت $commitHash به‌روز شد"); $state['commit_hash'] = $commitHash; - $this->logger->info('Software update completed successfully!'); - $this->writeOutput($output, 'Software update completed successfully!'); - $this->saveState($uuid, $state, $output, 'Update completed successfully'); + $this->logger->info('به‌روزرسانی نرم‌افزار با موفقیت انجام شد!'); + $this->writeOutput($output, 'به‌روزرسانی نرم‌افزار با موفقیت انجام شد!'); + $this->saveState($uuid, $state, $output, 'به‌روزرسانی با موفقیت تکمیل شد'); - $this->writeOutput($output, 'Cleaning up all temporary directories...'); + $this->writeOutput($output, 'پاکسازی تمام پوشه‌های موقت...'); $this->cleanupAllTempDirectories(); $lock->release(); return Command::SUCCESS; - } catch (\Exception $e) { - $this->logger->error('Update failed: ' . $e->getMessage()); - $this->writeOutput($output, 'An error occurred: ' . $e->getMessage() . ''); + } catch (ProcessFailedException $e) { + $errorMessage = $e->getProcess()->getErrorOutput() ?: $e->getMessage(); + $this->logger->error('فرآیند ناموفق بود: ' . $errorMessage); + $this->writeOutput($output, 'خطا در فرآیند: ' . $errorMessage . ''); + $this->rollback($gitHeadBefore, $cacheBackup, $dbBackup, $archiveBackup, $output); + $state['error'] = $errorMessage; + $this->saveState($uuid, $state, $output, 'فرآیند ناموفق بود و بازگردانی انجام شد'); + $lock->release(); + return Command::FAILURE; + } catch (\Exception $e) { + $this->logger->error('به‌روزرسانی ناموفق بود: ' . $e->getMessage()); + $this->writeOutput($output, 'خطا: ' . $e->getMessage() . ''); $this->rollback($gitHeadBefore, $cacheBackup, $dbBackup, $archiveBackup, $output); - $this->writeOutput($output, 'Update process aborted and rolled back.'); $state['error'] = $e->getMessage(); - $this->saveState($uuid, $state, $output, 'Update failed and rolled back'); + $this->saveState($uuid, $state, $output, 'به‌روزرسانی ناموفق بود و بازگردانی انجام شد'); $lock->release(); return Command::FAILURE; } finally { @@ -259,18 +266,25 @@ class UpdateSoftwareCommand extends Command private function writeOutput(OutputInterface $output, string $message): void { $output->writeln($message); - if (ob_get_level() > 0) { - ob_flush(); - flush(); - } + if (ob_get_level() >Please call flush(); + ob_flush(); } - private function runProcess(array $command, string $workingDir, OutputInterface $output, int $retries = 3): void + private function runProcess(array $command, string $workingDir, OutputInterface $output, int $retries = 3, bool $isComposer = false): void { $attempt = 0; while ($attempt < $retries) { try { - $process = new Process($command, $workingDir); + $env = []; + if ($isComposer) { + $env = [ + 'COMPOSER_ALLOW_SUPERUSER' => '1', + 'HOME' => '/var/www', + 'COMPOSER_HOME' => '/var/www/.composer', + ]; + } + + $process = new Process($command, $workingDir, $env); $process->setTimeout(3600); if ($output->isVerbose()) { $process->mustRun(function ($type, $buffer) use ($output) { @@ -280,19 +294,15 @@ class UpdateSoftwareCommand extends Command $process->mustRun(); $this->writeOutput($output, $process->getOutput()); } - $this->logger->info('Command executed successfully: ' . implode(' ', $command)); + $this->logger->info('دستور با موفقیت اجرا شد: ' . implode(' ', $command)); return; } catch (ProcessFailedException $e) { $attempt++; $errorMessage = $e->getProcess()->getErrorOutput() ?: $e->getMessage(); - if (stripos($errorMessage, 'permission denied') !== false || stripos($errorMessage, 'access denied') !== false) { - $this->logger->error("Permission error: $errorMessage"); - $this->writeOutput($output, "خطای دسترسی به فایل: $errorMessage"); - } - $this->logger->warning("Attempt $attempt failed for " . implode(' ', $command) . ": $errorMessage"); - $this->writeOutput($output, "Attempt $attempt failed: $errorMessage"); + $this->logger->warning("تلاش $attempt ناموفق برای " . implode(' ', $command) . ": $errorMessage"); + $this->writeOutput($output, "تلاش $attempt ناموفق: $errorMessage"); if ($attempt === $retries) { - throw new \RuntimeException('Command "' . implode(' ', $command) . '" failed after ' . $retries . ' attempts: ' . $errorMessage); + throw new \RuntimeException('دستور "' . implode(' ', $command) . '" پس از ' . $retries . ' تلاش ناموفق بود: ' . $errorMessage); } sleep(5); } @@ -309,8 +319,8 @@ class UpdateSoftwareCommand extends Command $process = new Process(['git', 'rev-parse', 'HEAD'], $this->rootDir); $process->run(); if (!$process->isSuccessful()) { - $this->logger->warning('Failed to get current Git HEAD: ' . $process->getErrorOutput()); - return 'unknown'; + $this->logger->warning('دریافت HEAD فعلی Git ناموفق بود: ' . $process->getErrorOutput()); + return 'ناشناخته'; } return trim($process->getOutput()); } @@ -318,18 +328,13 @@ class UpdateSoftwareCommand extends Command private function isUpToDate(): bool { try { - // دریافت آخرین تغییرات از ریموت $this->runProcess(['git', 'fetch', 'origin'], $this->rootDir, new \Symfony\Component\Console\Output\NullOutput()); - - // بررسی وضعیت شاخه فعلی $process = new Process(['git', 'status', '-uno'], $this->rootDir); $process->run(); $status = $process->getOutput(); - - // اگر پیام "Your branch is up to date" وجود داشته باشد، نرم‌افزار به‌روز است return strpos($status, 'Your branch is up to date') !== false; } catch (\Exception $e) { - $this->logger->warning('Failed to check if software is up to date: ' . $e->getMessage()); + $this->logger->warning('بررسی به‌روز بودن نرم‌افزار ناموفق بود: ' . $e->getMessage()); return false; } } @@ -344,7 +349,7 @@ class UpdateSoftwareCommand extends Command $envConfig = file_exists($this->appDir . '/.env.local.php') ? require $this->appDir . '/.env.local.php' : []; $dbUrl = $envConfig['DATABASE_URL'] ?? getenv('DATABASE_URL'); if (!$dbUrl) { - throw new \RuntimeException('Could not determine DATABASE_URL from .env.local.php or environment.'); + throw new \RuntimeException('تعیین DATABASE_URL از .env.local.php یا محیط ممکن نبود.'); } $urlParts = parse_url($dbUrl); @@ -377,7 +382,7 @@ class UpdateSoftwareCommand extends Command putenv("PGPASSWORD=$dbPass"); } } else { - throw new \RuntimeException("Unsupported database scheme: $dbScheme."); + throw new \RuntimeException("طرح دیتابیس پشتیبانی‌نشده: $dbScheme."); } $process = new Process($command, $this->rootDir); @@ -385,9 +390,9 @@ class UpdateSoftwareCommand extends Command $process->mustRun(); if (!file_exists($backupFile) || filesize($backupFile) === 0) { - throw new \RuntimeException('Failed to create database backup.'); + throw new \RuntimeException('ایجاد بکاپ دیتابیس ناموفق بود.'); } - $this->logger->info("Database backup created at: $backupFile (scheme: $dbScheme)"); + $this->logger->info("بکاپ دیتابیس در مسیر ایجاد شد: $backupFile (طرح: $dbScheme)"); } private function restoreArchive(string $backupFile): void @@ -396,7 +401,7 @@ class UpdateSoftwareCommand extends Command $this->runProcess(['mkdir', $this->archiveDir], $this->rootDir, new \Symfony\Component\Console\Output\NullOutput()); $this->runProcess(['tar', '-xf', $backupFile, '-C', $this->rootDir], $this->rootDir, new \Symfony\Component\Console\Output\NullOutput()); if (!is_dir($this->archiveDir)) { - throw new \RuntimeException('Failed to restore hesabixArchive from tar backup.'); + throw new \RuntimeException('بازگردانی hesabixArchive از بکاپ tar ناموفق بود.'); } } @@ -422,14 +427,14 @@ class UpdateSoftwareCommand extends Command private function rollback(?string $gitHeadBefore, ?string $cacheBackup, ?string $dbBackup, ?string $archiveBackup, OutputInterface $output): void { - $this->writeOutput($output, 'Rolling back changes...'); + $this->writeOutput($output, 'بازگردانی تغییرات...'); if ($gitHeadBefore) { try { $this->runProcess(['git', 'reset', '--hard', $gitHeadBefore], $this->rootDir, $output); - $this->logger->info('Git rolled back to ' . $gitHeadBefore); + $this->logger->info('Git به ' . $gitHeadBefore . ' بازگردانی شد'); } catch (\Exception $e) { - $this->logger->error('Git rollback failed: ' . $e->getMessage()); + $this->logger->error('بازگردانی Git ناموفق بود: ' . $e->getMessage()); } } @@ -437,9 +442,9 @@ class UpdateSoftwareCommand extends Command try { $this->runProcess(['rm', '-rf', $this->appDir . '/var/cache'], $this->rootDir, $output); $this->runProcess(['cp', '-r', $cacheBackup, $this->appDir . '/var/cache'], $this->rootDir, $output); - $this->logger->info('Cache rolled back'); + $this->logger->info('کش بازگردانی شد'); } catch (\Exception $e) { - $this->logger->error('Cache rollback failed: ' . $e->getMessage()); + $this->logger->error('بازگردانی کش ناموفق بود: ' . $e->getMessage()); } } @@ -448,7 +453,7 @@ class UpdateSoftwareCommand extends Command $envConfig = file_exists($this->appDir . '/.env.local.php') ? require $this->appDir . '/.env.local.php' : []; $dbUrl = $envConfig['DATABASE_URL'] ?? getenv('DATABASE_URL'); if (!$dbUrl) { - throw new \RuntimeException('Could not determine DATABASE_URL for rollback.'); + throw new \RuntimeException('تعیین DATABASE_URL برای بازگردانی ممکن نبود.'); } $urlParts = parse_url($dbUrl); @@ -481,23 +486,23 @@ class UpdateSoftwareCommand extends Command } $process = new Process($command, $this->rootDir); } else { - throw new \RuntimeException("Unsupported database scheme for rollback: $dbScheme."); + throw new \RuntimeException("طرح دیتابیس پشتیبانی‌نشده برای بازگردانی: $dbScheme."); } $process->setTimeout(3600); $process->mustRun(); - $this->logger->info('Database rolled back'); + $this->logger->info('دیتابیس بازگردانی شد'); } catch (\Exception $e) { - $this->logger->error('Database rollback failed: ' . $e->getMessage()); + $this->logger->error('بازگردانی دیتابیس ناموفق بود: ' . $e->getMessage()); } } if ($archiveBackup) { try { $this->restoreArchive($archiveBackup); - $this->logger->info('hesabixArchive rolled back'); + $this->logger->info('آرشیو hesabix بازگردانی شد'); } catch (\Exception $e) { - $this->logger->error('Archive rollback failed: ' . $e->getMessage()); + $this->logger->error('بازگردانی آرشیو ناموفق بود: ' . $e->getMessage()); } } } @@ -510,7 +515,7 @@ class UpdateSoftwareCommand extends Command foreach ($directories as $dir) { $dirName = basename($dir); if (!in_array($dirName, $protectedDirs)) { - $this->logger->info("Removing temporary directory: $dir"); + $this->logger->info("حذف پوشه موقت: $dir"); $this->runProcess(['rm', '-rf', $dir], $this->rootDir, new \Symfony\Component\Console\Output\NullOutput()); } } @@ -532,6 +537,32 @@ class UpdateSoftwareCommand extends Command $state['uuid'] = $uuid; $state['log'] = ($state['log'] ?? '') . ($output->getVerbosity() >= OutputInterface::VERBOSITY_NORMAL ? $message . "\n" : ''); file_put_contents($this->stateFile, json_encode($state, JSON_PRETTY_PRINT)); - $this->logger->debug('State saved to ' . $this->stateFile); + $this->logger->debug('وضعیت در مسیر ذخیره شد: ' . $this->stateFile); + } + + private function preUpdateChecks(OutputInterface $output): void + { + $this->writeOutput($output, 'اجرای بررسی‌های پیش از به‌روزرسانی...'); + $this->runProcess(['git', '--version'], $this->rootDir, $output, 1); + $this->runProcess(['composer', '--version'], $this->rootDir, $output, 1, true); + $this->runProcess(['php', '-v'], $this->rootDir, $output, 1); + $this->runProcess(['npm', '--version'], $this->rootDir, $output, 1); + + $process = new Process(['whoami'], $this->rootDir); + $process->run(); + $user = trim($process->getOutput()); + if ($user === 'root') { + $this->writeOutput($output, 'اجرای دستور به‌عنوان root ممکن است خطرناک باشد. توصیه می‌شود از کاربر غیر-root استفاده کنید.'); + $this->logger->warning('دستور به‌عنوان کاربر root اجرا شده است.'); + } + + $this->writeOutput($output, 'بررسی‌های پیش از به‌روزرسانی با موفقیت تکمیل شد.'); + } + + private function postUpdateChecks(OutputInterface $output): void + { + $this->writeOutput($output, 'اجرای بررسی‌های پس از به‌روزرسانی...'); + $this->runProcess(['php', 'bin/console', 'cache:pool:clear', 'cache.global_clearer'], $this-> definitivamente + $this->writeOutput($output, 'بررسی‌های پس از به‌روزرسانی با موفقیت تکمیل شد.'); } } \ No newline at end of file