You've already forked Atomcms-edit
refactor: integrate diagnostics into Commandocentrum and split EmulatorUpdateService
- Add DiagnosticRunner integration to Commandocentrum for system health display - Refactor EmulatorUpdateService from 2524 lines to 395 lines (facade pattern) - Extract EmulatorStatusService, EmulatorJarService, EmulatorSourceService - Extract EmulatorBuildService, EmulatorSqlService, EmulatorBackupService - Add shared EmulatorConfiguration trait for dependency injection - Preserve backward compatibility on all public methods
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Emulator;
|
||||
|
||||
use App\Services\Emulator\EmulatorSqlService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
class EmulatorBuildService
|
||||
{
|
||||
use EmulatorConfiguration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadConfiguration();
|
||||
}
|
||||
|
||||
public function buildFromSource(bool $force = false): array
|
||||
{
|
||||
$repo = $this->sourceRepo ?: $this->githubRepo;
|
||||
$branch = $this->sourceBranch ?: $this->githubBranch ?: 'main';
|
||||
|
||||
if (! $repo) {
|
||||
return ['success' => false, 'error' => 'Geen source repo geconfigureerd'];
|
||||
}
|
||||
|
||||
$sourcePath = $this->emulatorSourcePath;
|
||||
$serviceName = $this->emulatorService;
|
||||
|
||||
Log::info('[EmulatorBuild] Starting source build', [
|
||||
'repo' => $repo,
|
||||
'branch' => $branch,
|
||||
'path' => $sourcePath,
|
||||
]);
|
||||
|
||||
$this->ensureJavaInstalled();
|
||||
|
||||
Process::timeout(10)->run('mkdir -p ' . escapeshellarg(dirname((string) $sourcePath)));
|
||||
Process::timeout(10)->run('mkdir -p ' . escapeshellarg((string) $this->jarPath));
|
||||
Process::timeout(10)->run('chown -R www-data:www-data ' . escapeshellarg(dirname((string) $sourcePath)));
|
||||
|
||||
$maxRetries = 2;
|
||||
$lastError = '';
|
||||
|
||||
for ($retry = 0; $retry <= $maxRetries; $retry++) {
|
||||
Process::timeout(10)->run('chown -R www-data:www-data ' . escapeshellarg(dirname((string) $sourcePath)) . ' 2>/dev/null || true');
|
||||
Process::timeout(10)->run('chown -R www-data:www-data ' . escapeshellarg((string) $sourcePath) . ' 2>/dev/null || true');
|
||||
|
||||
if ($retry > 0) {
|
||||
Log::info('[EmulatorBuild] Retry attempt', ['attempt' => $retry]);
|
||||
Process::timeout(30)->run('rm -rf ' . escapeshellarg((string) $sourcePath));
|
||||
}
|
||||
|
||||
try {
|
||||
$existsCheck = Process::timeout(5)->run('[ -d ' . escapeshellarg((string) $sourcePath) . " ] && echo 'exists'");
|
||||
$sourceExists = $existsCheck->successful() && trim($existsCheck->output()) === 'exists';
|
||||
|
||||
$gitCheck = Process::timeout(5)->run('[ -d ' . escapeshellarg((string) $sourcePath) . "/.git ] && echo 'git'");
|
||||
$isGitRepo = $gitCheck->successful() && trim($gitCheck->output()) === 'git';
|
||||
|
||||
if ($sourceExists && $isGitRepo) {
|
||||
Log::info('[EmulatorBuild] Pulling latest changes');
|
||||
$commands = [
|
||||
'cd ' . escapeshellarg((string) $sourcePath) . ' && git fetch origin',
|
||||
'cd ' . escapeshellarg((string) $sourcePath) . ' && git checkout ' . escapeshellarg($branch),
|
||||
'cd ' . escapeshellarg((string) $sourcePath) . ' && git pull origin ' . escapeshellarg($branch),
|
||||
];
|
||||
} else {
|
||||
Log::info('[EmulatorBuild] Cloning repository');
|
||||
$commands = [
|
||||
'sudo rm -rf ' . escapeshellarg((string) $sourcePath) . ' 2>/dev/null || rm -rf ' . escapeshellarg((string) $sourcePath),
|
||||
'mkdir -p ' . escapeshellarg(dirname((string) $sourcePath)),
|
||||
'git clone --branch ' . escapeshellarg($branch) . ' --depth 1 https://github.com/' . escapeshellarg($repo) . '.git ' . escapeshellarg((string) $sourcePath),
|
||||
'chown -R www-data:www-data ' . escapeshellarg((string) $sourcePath),
|
||||
];
|
||||
}
|
||||
|
||||
$command = implode(' && ', $commands);
|
||||
$result = Process::timeout(300)->run($command);
|
||||
|
||||
if ($result->failed()) {
|
||||
$lastError = 'Git clone/pull failed: ' . substr($result->errorOutput(), 0, 300);
|
||||
Log::warning('[EmulatorBuild] Git operation failed', ['error' => $lastError, 'attempt' => $retry]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$buildCommands = $this->getBuildCommands($sourcePath);
|
||||
|
||||
Log::info('[EmulatorBuild] Running build', ['command' => $buildCommands]);
|
||||
$buildResult = Process::timeout(600)->run('cd ' . escapeshellarg((string) $sourcePath) . ' && ' . $buildCommands);
|
||||
|
||||
$hasSignalError = str_contains($buildResult->errorOutput(), 'signal') || str_contains($buildResult->output(), 'signal');
|
||||
|
||||
if ($hasSignalError) {
|
||||
Log::warning('[EmulatorBuild] Build process received signal, checking if JAR was built anyway');
|
||||
}
|
||||
|
||||
$jarPath = $this->findBuiltJar($sourcePath);
|
||||
|
||||
if ($jarPath) {
|
||||
Log::info('[EmulatorBuild] JAR found despite build status', ['jar' => $jarPath]);
|
||||
} elseif ($buildResult->failed() && ! $hasSignalError) {
|
||||
$lastError = 'Build failed: ' . substr($buildResult->errorOutput(), 0, 500);
|
||||
Log::warning('[EmulatorBuild] Build failed', ['error' => $lastError, 'attempt' => $retry]);
|
||||
|
||||
if ($retry < $maxRetries) {
|
||||
$cleanCommands = [
|
||||
'cd ' . escapeshellarg((string) $sourcePath) . ' && mvn clean 2>/dev/null || ./gradlew clean 2>/dev/null || true',
|
||||
];
|
||||
Process::timeout(60)->run(implode(' && ', $cleanCommands));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $jarPath) {
|
||||
$lastError = 'Build succeeded but JAR not found. Check build output.';
|
||||
Log::warning('[EmulatorBuild] JAR not found', ['attempt' => $retry]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->deployJar($jarPath, $serviceName);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$lastError = $e->getMessage();
|
||||
Log::error('[EmulatorBuild] Source build exception', ['error' => $lastError, 'attempt' => $retry]);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'Build mislukt na ' . ($maxRetries + 1) . ' pogingen. Laatste fout: ' . $lastError,
|
||||
];
|
||||
}
|
||||
|
||||
public function getBuildCommands(string $sourcePath): string
|
||||
{
|
||||
$pomPath = $sourcePath;
|
||||
$pomCheck = Process::timeout(5)->run("[ -f {$pomPath}/pom.xml ] && echo 'pom'");
|
||||
|
||||
if (! $pomCheck->successful() || trim($pomCheck->output()) !== 'pom') {
|
||||
$pomPath = $sourcePath . '/Emulator';
|
||||
$pomCheck = Process::timeout(5)->run("[ -f {$pomPath}/pom.xml ] && echo 'pom'");
|
||||
}
|
||||
|
||||
$gradlewPath = $sourcePath . '/gradlew';
|
||||
$gradlewCheck = Process::timeout(5)->run("[ -f {$gradlewPath} ] && echo 'gradlew'");
|
||||
|
||||
$gradlePath = $sourcePath . '/build.gradle';
|
||||
$gradleCheck = Process::timeout(5)->run("[ -f {$gradlePath} ] && echo 'gradle'");
|
||||
|
||||
if ($pomCheck->successful() && trim($pomCheck->output()) === 'pom') {
|
||||
return "cd {$pomPath} && mvn clean package -DskipTests 2>&1";
|
||||
}
|
||||
|
||||
if ($gradlewCheck->successful() && trim($gradlewCheck->output()) === 'gradlew') {
|
||||
return "cd {$sourcePath} && chmod +x gradlew && ./gradlew clean build -x test 2>&1";
|
||||
}
|
||||
|
||||
if ($gradleCheck->successful() && trim($gradleCheck->output()) === 'gradle') {
|
||||
return "cd {$sourcePath} && gradle clean build -x test 2>&1";
|
||||
}
|
||||
|
||||
return "cd {$sourcePath} && ls -la";
|
||||
}
|
||||
|
||||
public function findBuiltJar(string $sourcePath): ?string
|
||||
{
|
||||
$patterns = [
|
||||
$sourcePath . '/target/*.jar',
|
||||
$sourcePath . '/build/libs/*.jar',
|
||||
$sourcePath . '/*/*.jar',
|
||||
$sourcePath . '/*.jar',
|
||||
$sourcePath . '/Emulator/target/*.jar',
|
||||
$sourcePath . '/Emulator/build/libs/*.jar',
|
||||
$sourcePath . '/Emulator/*/*.jar',
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
$result = Process::timeout(10)->run('ls -t ' . $pattern . ' 2>/dev/null | head -1');
|
||||
if ($result->successful()) {
|
||||
$jarPath = trim($result->output());
|
||||
if ($jarPath !== '' && $jarPath !== '0' && str_contains($jarPath, '.jar')) {
|
||||
return $jarPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function deployJar(string $jarPath, string $serviceName): array
|
||||
{
|
||||
$jarName = basename($jarPath);
|
||||
$version = $this->extractVersionFromFilename($jarName);
|
||||
if ($version === '' || $version === '0') {
|
||||
$version = date('Y.m.d');
|
||||
}
|
||||
|
||||
$deployCommands = [
|
||||
'mkdir -p ' . escapeshellarg((string) $this->jarPath),
|
||||
'chown -R www-data:www-data ' . escapeshellarg((string) $this->jarPath),
|
||||
'if ls ' . escapeshellarg((string) $this->jarPath) . '/*.jar 1>/dev/null 2>&1; then mkdir -p ' . escapeshellarg((string) $this->jarPath) . '/backup && mv ' . escapeshellarg((string) $this->jarPath) . '/*.jar ' . escapeshellarg((string) $this->jarPath) . '/backup/; fi',
|
||||
'cp -f ' . escapeshellarg($jarPath) . ' ' . escapeshellarg((string) $this->jarPath) . '/' . escapeshellarg($jarName),
|
||||
'chown www-data:www-data ' . escapeshellarg((string) $this->jarPath) . '/' . escapeshellarg($jarName),
|
||||
'chmod 755 ' . escapeshellarg((string) $this->jarPath) . '/' . escapeshellarg($jarName),
|
||||
'ls -la ' . escapeshellarg((string) $this->jarPath) . '/',
|
||||
'systemctl restart ' . escapeshellarg((string) $serviceName) . ' 2>&1 || service ' . escapeshellarg((string) $serviceName) . ' restart 2>&1 || true',
|
||||
];
|
||||
|
||||
$deployCommand = implode(' && ', $deployCommands);
|
||||
|
||||
Log::info('[EmulatorBuild] Deploying jar', [
|
||||
'source' => $jarPath,
|
||||
'destination' => "{$this->jarPath}/{$jarName}",
|
||||
]);
|
||||
|
||||
$deployResult = Process::timeout(60)->run($deployCommand);
|
||||
|
||||
if (! $deployResult->successful()) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'Deploy failed: ' . substr($deployResult->errorOutput(), 0, 300),
|
||||
];
|
||||
}
|
||||
|
||||
$sourceService = new EmulatorSourceService;
|
||||
$sourceInfo = $sourceService->checkForUpdates();
|
||||
$installedDate = $sourceInfo['latest_timestamp'] ?? time();
|
||||
|
||||
$this->settings->set('emulator_version', $version);
|
||||
$this->settings->set('emulator_jar_installed_date', (string) $installedDate);
|
||||
$this->settings->set('emulator_source_commit', $sourceInfo['latest_sha'] ?? 'unknown');
|
||||
$this->settings->set('emulator_source_date', (string) $installedDate);
|
||||
|
||||
$currentBranch = $this->sourceBranch ?: $this->githubBranch ?: 'main';
|
||||
$this->settings->set('emulator_installed_branch', $currentBranch);
|
||||
|
||||
$sqlService = new EmulatorSqlService;
|
||||
$sqlService->runUpdates();
|
||||
|
||||
Log::info('[EmulatorBuild] Source build successful');
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'version' => $version,
|
||||
'jar' => $jarName,
|
||||
'built' => true,
|
||||
'message' => "✅ Emulator vanaf source gebouwd!\n📦 {$jarName}\n🔄 Service herstart",
|
||||
];
|
||||
}
|
||||
|
||||
private function ensureJavaInstalled(): void
|
||||
{
|
||||
$javaCheck = Process::timeout(5)->run('java -version 2>&1');
|
||||
if (! $javaCheck->successful()) {
|
||||
Log::warning('[EmulatorBuild] Java not found, attempting to install');
|
||||
Process::timeout(180)->run('apt-get update && apt-get install -y default-jdk 2>&1');
|
||||
}
|
||||
|
||||
$mavenCheck = Process::timeout(5)->run('which mvn');
|
||||
if (! $mavenCheck->successful()) {
|
||||
Log::warning('[EmulatorBuild] Maven not found, attempting to install');
|
||||
Process::timeout(180)->run('apt-get install -y maven 2>&1');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user