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:
+273
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Emulator;
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EmulatorSourceService
|
||||
{
|
||||
use EmulatorConfiguration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadConfiguration();
|
||||
}
|
||||
|
||||
public function checkForUpdates(): ?array
|
||||
{
|
||||
$repo = $this->sourceRepo ?: $this->githubRepo;
|
||||
$branch = $this->sourceBranch ?: $this->githubBranch ?: 'main';
|
||||
|
||||
if (! $repo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$localCheck = $this->checkLocalSourceUpdates();
|
||||
if ($localCheck !== null) {
|
||||
return $localCheck;
|
||||
}
|
||||
|
||||
return $this->checkRemoteSourceUpdates($repo, $branch);
|
||||
}
|
||||
|
||||
public function isSourceBuildAvailable(): bool
|
||||
{
|
||||
$hasRepo = ! in_array($this->sourceRepo, [null, '', '0'], true) || ! in_array($this->githubRepo, [null, '', '0'], true);
|
||||
$hasPath = ! in_array($this->emulatorSourcePath, [null, '', '0'], true);
|
||||
|
||||
if (! $hasRepo || ! $hasPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = Process::timeout(5)->run("[ -d {$this->emulatorSourcePath} ] && echo 'exists' || echo 'not_exists'");
|
||||
|
||||
return trim($result->output()) === 'exists';
|
||||
} catch (\Exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkLocalSourceUpdates(): ?array
|
||||
{
|
||||
$sourcePath = $this->emulatorSourcePath;
|
||||
|
||||
$existsCheck = Process::timeout(5)->run("[ -d {$sourcePath} ] && echo 'exists'");
|
||||
if (! $existsCheck->successful() || trim($existsCheck->output()) !== 'exists') {
|
||||
return $this->checkSourceByCloning();
|
||||
}
|
||||
|
||||
try {
|
||||
$gitCheck = Process::timeout(5)->run("cd {$sourcePath} && git rev-parse --is-inside-work-tree 2>/dev/null");
|
||||
if (! $gitCheck->successful()) {
|
||||
return $this->checkSourceByCloning();
|
||||
}
|
||||
|
||||
$currentCommitResult = Process::timeout(5)->run("cd {$sourcePath} && git rev-parse HEAD");
|
||||
if (! $currentCommitResult->successful()) {
|
||||
return null;
|
||||
}
|
||||
$currentSha = trim($currentCommitResult->output());
|
||||
|
||||
$fetchResult = Process::timeout(30)->run("cd {$sourcePath} && git fetch origin 2>&1");
|
||||
if ($fetchResult->failed()) {
|
||||
Log::debug('[EmulatorSource] Git fetch failed, trying local check only');
|
||||
}
|
||||
|
||||
$branch = $this->sourceBranch ?: $this->githubBranch ?: 'main';
|
||||
$latestResult = Process::timeout(5)->run("cd {$sourcePath} && git rev-parse origin/{$branch} 2>/dev/null || git rev-parse HEAD");
|
||||
if (! $latestResult->successful()) {
|
||||
return null;
|
||||
}
|
||||
$latestSha = trim($latestResult->output());
|
||||
|
||||
$dateResult = Process::timeout(5)->run("cd {$sourcePath} && git log -1 --format='%ci' {$latestSha}");
|
||||
$latestDate = null;
|
||||
$latestTimestamp = time();
|
||||
if ($dateResult->successful()) {
|
||||
$latestDate = trim($dateResult->output(), "'");
|
||||
if ($latestDate !== '' && $latestDate !== '0') {
|
||||
$latestTimestamp = strtotime($latestDate);
|
||||
}
|
||||
}
|
||||
|
||||
$this->persistSourceCommitInfo($latestSha, $latestTimestamp);
|
||||
|
||||
$msgResult = Process::timeout(5)->run("cd {$sourcePath} && git log -1 --format='%s' {$latestSha}");
|
||||
$latestMessage = $msgResult->successful() ? trim($msgResult->output()) : '';
|
||||
|
||||
$authorResult = Process::timeout(5)->run("cd {$sourcePath} && git log -1 --format='%an' {$latestSha}");
|
||||
$latestAuthor = $authorResult->successful() ? trim($authorResult->output()) : '';
|
||||
|
||||
$storedSha = $this->settings->getOrDefault('emulator_source_commit', null);
|
||||
$storedDate = $this->settings->getOrDefault('emulator_source_date', null);
|
||||
|
||||
$isUpdate = $storedSha !== null && $storedSha !== $latestSha;
|
||||
if ($storedSha === null) {
|
||||
$isUpdate = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'has_update' => $isUpdate,
|
||||
'latest_sha' => $latestSha,
|
||||
'latest_date' => $latestDate,
|
||||
'latest_timestamp' => $latestTimestamp,
|
||||
'latest_message' => $latestMessage,
|
||||
'latest_author' => $latestAuthor,
|
||||
'stored_sha' => $storedSha,
|
||||
'stored_date' => $storedDate,
|
||||
'source' => 'local',
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('[EmulatorSource] Local source check failed: ' . $e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkSourceByCloning(): ?array
|
||||
{
|
||||
$repo = $this->sourceRepo ?: $this->githubRepo;
|
||||
$branch = $this->sourceBranch ?: $this->githubBranch ?: 'main';
|
||||
|
||||
if (! $repo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repo = preg_replace('#/tree/[^/]+/.*$#', '', $repo);
|
||||
$repo = str_replace(['https://github.com/', 'http://github.com/'], '', $repo);
|
||||
$repo = rtrim($repo, '/');
|
||||
|
||||
try {
|
||||
$tempDir = '/tmp/emulator-source-check-' . Str::random(8);
|
||||
|
||||
$cloneResult = Process::timeout(120)->run(
|
||||
"git clone --branch {$branch} --depth 1 https://github.com/{$repo}.git {$tempDir} 2>&1",
|
||||
);
|
||||
|
||||
if ($cloneResult->failed()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$shaResult = Process::timeout(5)->run("cd {$tempDir} && git rev-parse HEAD");
|
||||
$latestSha = $shaResult->successful() ? trim($shaResult->output()) : '';
|
||||
|
||||
$dateResult = Process::timeout(5)->run("cd {$tempDir} && git log -1 --format='%ci'");
|
||||
$latestDate = null;
|
||||
$latestTimestamp = time();
|
||||
if ($dateResult->successful()) {
|
||||
$latestDate = trim($dateResult->output());
|
||||
if ($latestDate !== '' && $latestDate !== '0') {
|
||||
$latestTimestamp = strtotime($latestDate);
|
||||
}
|
||||
}
|
||||
|
||||
$this->persistSourceCommitInfo($latestSha, $latestTimestamp);
|
||||
|
||||
$msgResult = Process::timeout(5)->run("cd {$tempDir} && git log -1 --format='%s'");
|
||||
$latestMessage = $msgResult->successful() ? trim($msgResult->output()) : '';
|
||||
|
||||
$authorResult = Process::timeout(5)->run("cd {$tempDir} && git log -1 --format='%an'");
|
||||
$latestAuthor = $authorResult->successful() ? trim($authorResult->output()) : '';
|
||||
|
||||
Process::timeout(10)->run("rm -rf {$tempDir}");
|
||||
|
||||
$storedSha = $this->settings->getOrDefault('emulator_source_commit', null);
|
||||
$storedDate = $this->settings->getOrDefault('emulator_source_date', null);
|
||||
|
||||
$isUpdate = $storedSha !== null && $storedSha !== $latestSha;
|
||||
if ($storedSha === null) {
|
||||
$isUpdate = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'has_update' => $isUpdate,
|
||||
'latest_sha' => $latestSha,
|
||||
'latest_date' => $latestDate,
|
||||
'latest_timestamp' => $latestTimestamp,
|
||||
'latest_message' => $latestMessage,
|
||||
'latest_author' => $latestAuthor,
|
||||
'stored_sha' => $storedSha,
|
||||
'stored_date' => $storedDate,
|
||||
'source' => 'cloned',
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('[EmulatorSource] Source clone check failed: ' . $e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkRemoteSourceUpdates(string $repo, string $branch): ?array
|
||||
{
|
||||
try {
|
||||
$response = Http::timeout(10)
|
||||
->withHeaders([
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'User-Agent' => 'AtomCMS-Emulator-Updater',
|
||||
])
|
||||
->get("https://api.github.com/repos/{$repo}/commits", [
|
||||
'sha' => $branch,
|
||||
'per_page' => 1,
|
||||
]);
|
||||
|
||||
if (! $response->successful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$commits = $response->json();
|
||||
|
||||
if (empty($commits) || ! isset($commits[0]['sha'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$latestCommit = $commits[0];
|
||||
$latestSha = $latestCommit['sha'];
|
||||
$latestDate = $latestCommit['commit']['committer']['date'] ?? null;
|
||||
$latestTimestamp = $latestDate ? strtotime((string) $latestDate) : time();
|
||||
|
||||
$this->persistSourceCommitInfo($latestSha, $latestTimestamp);
|
||||
|
||||
$installedDate = $this->settings->getOrDefault('emulator_jar_installed_date', null);
|
||||
$storedSha = $this->settings->getOrDefault('emulator_source_commit', null);
|
||||
$storedDate = $this->settings->getOrDefault('emulator_source_date', null);
|
||||
|
||||
if ($storedSha !== null && $storedSha === $latestSha) {
|
||||
$isUpdate = false;
|
||||
} elseif ($storedSha !== null && $storedSha !== $latestSha) {
|
||||
$isUpdate = true;
|
||||
} elseif ($installedDate !== null) {
|
||||
$installedTimestamp = is_numeric($installedDate) ? (int) $installedDate : strtotime((string) $installedDate);
|
||||
$isUpdate = $installedTimestamp < $latestTimestamp;
|
||||
} else {
|
||||
$isUpdate = false;
|
||||
}
|
||||
|
||||
return [
|
||||
'has_update' => $isUpdate,
|
||||
'latest_sha' => $latestSha,
|
||||
'latest_date' => $latestDate,
|
||||
'latest_timestamp' => $latestTimestamp,
|
||||
'latest_message' => $latestCommit['commit']['message'] ?? '',
|
||||
'latest_author' => $latestCommit['commit']['author']['name'] ?? '',
|
||||
'stored_sha' => $storedSha,
|
||||
'stored_date' => $storedDate,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::warning('[EmulatorSource] Could not check source updates via GitHub API', ['error' => $e->getMessage()]);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function persistSourceCommitInfo(string $sha, int $timestamp): void
|
||||
{
|
||||
$this->settings->set('emulator_source_commit', $sha);
|
||||
$this->settings->set('emulator_source_date', (string) $timestamp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user