update auto updater
This commit is contained in:
parent
f82bd6ac8d
commit
b3fad9ee6c
|
@ -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, '<error>Another update process is currently running. Please try again later.</error>');
|
||||
$this->logger->warning('Update attempt blocked due to existing lock.');
|
||||
$this->writeOutput($output, '<error>یک فرآیند بهروزرسانی دیگر در حال اجراست. لطفاً بعداً تلاش کنید.</error>');
|
||||
$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, '<info>The software is already up to date with the remote repository.</info>');
|
||||
$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, '<info>نرمافزار از قبل با مخزن ریموت بهروز است.</info>');
|
||||
$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, '<info>Software update completed successfully!</info>');
|
||||
$this->saveState($uuid, $state, $output, 'Update completed successfully');
|
||||
$this->logger->info('بهروزرسانی نرمافزار با موفقیت انجام شد!');
|
||||
$this->writeOutput($output, '<info>بهروزرسانی نرمافزار با موفقیت انجام شد!</info>');
|
||||
$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, '<error>An error occurred: ' . $e->getMessage() . '</error>');
|
||||
} catch (ProcessFailedException $e) {
|
||||
$errorMessage = $e->getProcess()->getErrorOutput() ?: $e->getMessage();
|
||||
$this->logger->error('فرآیند ناموفق بود: ' . $errorMessage);
|
||||
$this->writeOutput($output, '<error>خطا در فرآیند: ' . $errorMessage . '</error>');
|
||||
$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, '<error>خطا: ' . $e->getMessage() . '</error>');
|
||||
$this->rollback($gitHeadBefore, $cacheBackup, $dbBackup, $archiveBackup, $output);
|
||||
$this->writeOutput($output, '<comment>Update process aborted and rolled back.</comment>');
|
||||
$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) {
|
||||
if (ob_get_level() >Please call flush();
|
||||
ob_flush();
|
||||
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, "<error>خطای دسترسی به فایل: $errorMessage</error>");
|
||||
}
|
||||
$this->logger->warning("Attempt $attempt failed for " . implode(' ', $command) . ": $errorMessage");
|
||||
$this->writeOutput($output, "<comment>Attempt $attempt failed: $errorMessage</comment>");
|
||||
$this->logger->warning("تلاش $attempt ناموفق برای " . implode(' ', $command) . ": $errorMessage");
|
||||
$this->writeOutput($output, "<comment>تلاش $attempt ناموفق: $errorMessage</comment>");
|
||||
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, '<warning>اجرای دستور بهعنوان root ممکن است خطرناک باشد. توصیه میشود از کاربر غیر-root استفاده کنید.</warning>');
|
||||
$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, 'بررسیهای پس از بهروزرسانی با موفقیت تکمیل شد.');
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue