edit in updateCore
This commit is contained in:
parent
a25d80d437
commit
11526aa8b8
11537
hesabixCore/composer.lock
generated
11537
hesabixCore/composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -64,7 +64,6 @@ class UpdateSoftwareCommand extends Command
|
||||||
mkdir(dirname($this->stateFile), 0755, true);
|
mkdir(dirname($this->stateFile), 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// اگر فایل وضعیت وجود ندارد، آن را ایجاد کن
|
|
||||||
if (!file_exists($this->stateFile)) {
|
if (!file_exists($this->stateFile)) {
|
||||||
file_put_contents($this->stateFile, json_encode([
|
file_put_contents($this->stateFile, json_encode([
|
||||||
'uuid' => Uuid::uuid4()->toString(),
|
'uuid' => Uuid::uuid4()->toString(),
|
||||||
|
@ -79,7 +78,7 @@ class UpdateSoftwareCommand extends Command
|
||||||
$this->writeOutput($output, "Starting software update (UUID: $uuid) in {$this->env} mode");
|
$this->writeOutput($output, "Starting software update (UUID: $uuid) in {$this->env} mode");
|
||||||
|
|
||||||
$state = $this->loadState($uuid);
|
$state = $this->loadState($uuid);
|
||||||
$state['log'] = $state['log'] ?? ''; // اطمینان از وجود کلید log
|
$state['log'] = $state['log'] ?? '';
|
||||||
|
|
||||||
if ($this->isUpToDate()) {
|
if ($this->isUpToDate()) {
|
||||||
$this->writeOutput($output, '<info>The software is already up to date with the remote repository.</info>');
|
$this->writeOutput($output, '<info>The software is already up to date with the remote repository.</info>');
|
||||||
|
@ -125,7 +124,6 @@ class UpdateSoftwareCommand extends Command
|
||||||
|
|
||||||
if (!in_array('git_pull', $state['completedSteps'])) {
|
if (!in_array('git_pull', $state['completedSteps'])) {
|
||||||
$this->writeOutput($output, 'Setting up tracking for master branch...');
|
$this->writeOutput($output, 'Setting up tracking for master branch...');
|
||||||
// تنظیم ردیابی شاخه master به origin/master
|
|
||||||
$this->runProcess(['git', 'branch', '--set-upstream-to=origin/master', 'master'], $this->rootDir, $output, 1);
|
$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, 'Pulling latest changes from GitHub...');
|
||||||
|
@ -150,6 +148,18 @@ class UpdateSoftwareCommand extends Command
|
||||||
$this->saveState($uuid, $state, $output, 'Dependencies installed');
|
$this->saveState($uuid, $state, $output, 'Dependencies installed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!in_array('composer_install_core', $state['completedSteps'])) {
|
||||||
|
$this->writeOutput($output, 'Installing dependencies in hesabixCore...');
|
||||||
|
$composerCommand = ['composer', 'install', '--optimize-autoloader'];
|
||||||
|
if ($this->env !== 'dev') {
|
||||||
|
$composerCommand[] = '--no-dev';
|
||||||
|
$composerCommand[] = '--no-scripts';
|
||||||
|
}
|
||||||
|
$this->runProcess($composerCommand, $this->rootDir . '/hesabixCore', $output, 3);
|
||||||
|
$state['completedSteps'][] = 'composer_install_core';
|
||||||
|
$this->saveState($uuid, $state, $output, 'Dependencies installed in hesabixCore');
|
||||||
|
}
|
||||||
|
|
||||||
if (!in_array('cache_clear', $state['completedSteps'])) {
|
if (!in_array('cache_clear', $state['completedSteps'])) {
|
||||||
$this->writeOutput($output, 'Clearing cache...');
|
$this->writeOutput($output, 'Clearing cache...');
|
||||||
$cacheBackupDir = $this->backupDir . '/' . Uuid::uuid4();
|
$cacheBackupDir = $this->backupDir . '/' . Uuid::uuid4();
|
||||||
|
@ -258,6 +268,10 @@ class UpdateSoftwareCommand extends Command
|
||||||
} catch (ProcessFailedException $e) {
|
} catch (ProcessFailedException $e) {
|
||||||
$attempt++;
|
$attempt++;
|
||||||
$errorMessage = $e->getProcess()->getErrorOutput() ?: $e->getMessage();
|
$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->logger->warning("Attempt $attempt failed for " . implode(' ', $command) . ": $errorMessage");
|
||||||
$this->writeOutput($output, "<comment>Attempt $attempt failed: $errorMessage</comment>");
|
$this->writeOutput($output, "<comment>Attempt $attempt failed: $errorMessage</comment>");
|
||||||
if ($attempt === $retries) {
|
if ($attempt === $retries) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Controller\System;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Connection;
|
||||||
|
@ -109,7 +110,6 @@ final class UpdateCoreController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isRunning) {
|
if (!$isRunning) {
|
||||||
// عملیات موفق بوده، فایلهای update_state_*.json رو حذف کن
|
|
||||||
$backupDir = $this->getParameter('kernel.project_dir') . '/../backup';
|
$backupDir = $this->getParameter('kernel.project_dir') . '/../backup';
|
||||||
$stateFiles = glob($backupDir . '/update_state_*.json');
|
$stateFiles = glob($backupDir . '/update_state_*.json');
|
||||||
foreach ($stateFiles as $file) {
|
foreach ($stateFiles as $file) {
|
||||||
|
@ -133,6 +133,49 @@ final class UpdateCoreController extends AbstractController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/api/admin/updatecore/stream', name: 'api_admin_updatecore_stream', methods: ['GET'])]
|
||||||
|
public function api_admin_updatecore_stream(Request $request): StreamedResponse|JsonResponse
|
||||||
|
{
|
||||||
|
$uuid = $request->query->get('uuid');
|
||||||
|
if (!$uuid) {
|
||||||
|
return new JsonResponse(['status' => 'error', 'message' => 'UUID is required'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stateFile = $this->getParameter('kernel.project_dir') . '/../backup/update_state_' . $uuid . '.json';
|
||||||
|
|
||||||
|
return new StreamedResponse(function () use ($stateFile) {
|
||||||
|
header('Content-Type: text/event-stream');
|
||||||
|
header('Cache-Control: no-cache');
|
||||||
|
header('Connection: keep-alive');
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!file_exists($stateFile)) {
|
||||||
|
echo "data: " . json_encode(['status' => 'idle', 'output' => '']) . "\n\n";
|
||||||
|
ob_flush();
|
||||||
|
flush();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = json_decode(file_get_contents($stateFile), true) ?? ['log' => ''];
|
||||||
|
$output = $state['log'] ?? '';
|
||||||
|
|
||||||
|
$isRunning = !isset($state['error']) &&
|
||||||
|
!in_array('post_update_test', $state['completedSteps'] ?? []);
|
||||||
|
|
||||||
|
$status = $state['error'] ? 'error' : ($isRunning ? 'running' : 'success');
|
||||||
|
echo "data: " . json_encode(['status' => $status, 'output' => $output]) . "\n\n";
|
||||||
|
ob_flush();
|
||||||
|
flush();
|
||||||
|
|
||||||
|
if (!$isRunning) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[Route('/api/admin/updatecore/commits', name: 'api_admin_updatecore_commits', methods: ['GET'])]
|
#[Route('/api/admin/updatecore/commits', name: 'api_admin_updatecore_commits', methods: ['GET'])]
|
||||||
public function api_admin_updatecore_commits(): JsonResponse
|
public function api_admin_updatecore_commits(): JsonResponse
|
||||||
{
|
{
|
||||||
|
@ -215,4 +258,121 @@ final class UpdateCoreController extends AbstractController
|
||||||
'dbVersion' => $dbVersion,
|
'dbVersion' => $dbVersion,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/api/admin/updatecore/clear-cache', name: 'api_admin_updatecore_clear_cache', methods: ['POST'])]
|
||||||
|
public function api_admin_updatecore_clear_cache(): JsonResponse
|
||||||
|
{
|
||||||
|
$projectDir = $this->getParameter('kernel.project_dir');
|
||||||
|
$env = $this->getParameter('kernel.environment');
|
||||||
|
|
||||||
|
$process = new Process(['php', 'bin/console', 'cache:clear', "--env=$env"], $projectDir);
|
||||||
|
$process->setTimeout(300);
|
||||||
|
$process->run();
|
||||||
|
|
||||||
|
if (!$process->isSuccessful()) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Failed to clear cache: ' . $process->getErrorOutput(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'success',
|
||||||
|
'output' => $process->getOutput(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/api/admin/updatecore/change-env', name: 'api_admin_updatecore_change_env', methods: ['POST'])]
|
||||||
|
public function api_admin_updatecore_change_env(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$newEnv = $request->getPayload()->get('env');
|
||||||
|
|
||||||
|
if (!$newEnv || !in_array($newEnv, ['dev', 'prod'])) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Invalid environment',
|
||||||
|
'output' => 'خطا: محیط نامعتبر است',
|
||||||
|
'debug' => 'Received env: ' . var_export($newEnv, true)
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$projectDir = $this->getParameter('kernel.project_dir');
|
||||||
|
$envFile = $projectDir . '/.env.local.php';
|
||||||
|
$composerLock = $projectDir . '/composer.lock';
|
||||||
|
$output = '';
|
||||||
|
|
||||||
|
// بارگذاری تنظیمات از .env.local.php و تغییر APP_ENV
|
||||||
|
$envConfig = file_exists($envFile) ? require $envFile : [];
|
||||||
|
$envConfig['APP_ENV'] = $newEnv;
|
||||||
|
file_put_contents($envFile, '<?php return ' . var_export($envConfig, true) . ';');
|
||||||
|
$output .= "حالت به $newEnv تغییر کرد\n";
|
||||||
|
|
||||||
|
// حذف composer.lock
|
||||||
|
if (file_exists($composerLock)) {
|
||||||
|
unlink($composerLock);
|
||||||
|
$output .= "فایل composer.lock حذف شد\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// تنظیم متغیرهای محیطی حداقلی برای Composer
|
||||||
|
$env = [
|
||||||
|
'HOME' => sys_get_temp_dir(), // استفاده از دایرکتوری موقت سیستم
|
||||||
|
'COMPOSER_HOME' => sys_get_temp_dir() . '/composer' // دایرکتوری موقت برای Composer
|
||||||
|
];
|
||||||
|
|
||||||
|
// چک کردن نصب بودن Composer در سطح سیستم
|
||||||
|
$composerCheck = new Process(['composer', '--version'], $projectDir, $env);
|
||||||
|
$composerCheck->run();
|
||||||
|
if (!$composerCheck->isSuccessful()) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Composer is not installed',
|
||||||
|
'output' => $output . "خطا: Composer روی سرور نصب نیست. لطفاً Composer را نصب کنید.\n" . $composerCheck->getErrorOutput()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
$output .= "Composer نسخه " . trim($composerCheck->getOutput()) . " تشخیص داده شد\n";
|
||||||
|
|
||||||
|
// اجرای composer install
|
||||||
|
$composerCommand = ['composer', 'install', '--optimize-autoloader'];
|
||||||
|
if ($newEnv !== 'dev') {
|
||||||
|
$composerCommand[] = '--no-dev';
|
||||||
|
$composerCommand[] = '--no-scripts';
|
||||||
|
}
|
||||||
|
$composerProcess = new Process($composerCommand, $projectDir, $env);
|
||||||
|
$composerProcess->setTimeout(600);
|
||||||
|
$composerProcess->run();
|
||||||
|
if (!$composerProcess->isSuccessful()) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Failed to update dependencies',
|
||||||
|
'output' => $output . "خطا در بهروزرسانی وابستگیها: " . $composerProcess->getErrorOutput(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
$output .= "وابستگیها با موفقیت بهروزرسانی شدند\n" . $composerProcess->getOutput();
|
||||||
|
|
||||||
|
// خالی کردن کش
|
||||||
|
$cacheProcess = new Process(['php', 'bin/console', 'cache:clear', "--env=$newEnv"], $projectDir, $env);
|
||||||
|
$cacheProcess->setTimeout(300);
|
||||||
|
$cacheProcess->run();
|
||||||
|
if (!$cacheProcess->isSuccessful()) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Failed to clear cache',
|
||||||
|
'output' => $output . "خطا در پاک کردن کش: " . $cacheProcess->getErrorOutput(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
$output .= "کش با موفقیت پاک شد\n" . $cacheProcess->getOutput();
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => "حالت به $newEnv تغییر کرد، وابستگیها بهروزرسانی شدند و کش پاک شد",
|
||||||
|
'output' => $output,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/api/admin/updatecore/current-env', name: 'api_admin_updatecore_current_env', methods: ['GET'])]
|
||||||
|
public function api_admin_updatecore_current_env(): JsonResponse
|
||||||
|
{
|
||||||
|
$env = $this->getParameter('kernel.environment');
|
||||||
|
return new JsonResponse(['env' => $env]);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue