Bridge: fetch stable URL from MokoOnyx updates.xml, fix double-exec
Some checks failed
Repo Health / Access control (push) Successful in 1s
Auto-Update SHA Hash / Update SHA-256 Hash in updates.xml (release) Failing after 5s
Repo Health / Release configuration (push) Failing after 3s
Repo Health / Scripts governance (push) Successful in 3s
Repo Health / Repository health (push) Failing after 3s
Some checks failed
Repo Health / Access control (push) Successful in 1s
Auto-Update SHA Hash / Update SHA-256 Hash in updates.xml (release) Failing after 5s
Repo Health / Release configuration (push) Failing after 3s
Repo Health / Scripts governance (push) Successful in 3s
Repo Health / Repository health (push) Failing after 3s
- Remove hardcoded RELEASE_URL, discover from updates.xml stable channel - Add discoverStableUrl() to parse MokoOnyx updates.xml at runtime - Extract httpGet() helper for reuse across download + XML fetch - Remove bridge call from update() — postflight() handles it - Always targets stable channel for production-safe installs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,8 +28,11 @@ class MokoBridgeMigration
|
||||
private const OLD_DISPLAY = 'MokoCassiopeia';
|
||||
private const NEW_DISPLAY = 'MokoOnyx';
|
||||
|
||||
/** URL to the latest MokoOnyx stable release ZIP */
|
||||
private const RELEASE_URL = 'https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/download/v01/mokoonyx-01.00.00.zip';
|
||||
/** Raw URL for MokoOnyx updates.xml on main — used to discover the stable download URL */
|
||||
private const UPDATES_XML_URL = 'https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/updates.xml';
|
||||
|
||||
/** Fallback URL if updates.xml cannot be parsed */
|
||||
private const FALLBACK_URL = 'https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/download/v01/mokoonyx-01.00.00.zip';
|
||||
|
||||
/**
|
||||
* Run the full migration.
|
||||
@@ -85,15 +88,94 @@ class MokoBridgeMigration
|
||||
|
||||
/**
|
||||
* Download the MokoOnyx ZIP to Joomla's tmp directory.
|
||||
*
|
||||
* Reads MokoOnyx's updates.xml on main to discover the current stable
|
||||
* download URL, falling back to a hardcoded URL if parsing fails.
|
||||
*/
|
||||
private static function downloadRelease(): ?string
|
||||
{
|
||||
$tmpDir = Factory::getApplication()->get('tmp_path', JPATH_ROOT . '/tmp');
|
||||
$zipPath = $tmpDir . '/mokoonyx-install.zip';
|
||||
|
||||
// 1. Discover the stable download URL from MokoOnyx's updates.xml
|
||||
$releaseUrl = self::discoverStableUrl();
|
||||
if (!$releaseUrl) {
|
||||
self::log('Bridge: could not discover release URL from updates.xml, using fallback');
|
||||
$releaseUrl = self::FALLBACK_URL;
|
||||
}
|
||||
|
||||
self::log('Bridge: downloading MokoOnyx from ' . $releaseUrl);
|
||||
|
||||
// 2. Download the ZIP
|
||||
$content = self::httpGet($releaseUrl);
|
||||
|
||||
if ($content === false || strlen($content) < 1000) {
|
||||
self::log('Bridge: failed to download MokoOnyx ZIP from ' . $releaseUrl, 'error');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file_put_contents($zipPath, $content) === false) {
|
||||
self::log('Bridge: failed to write ZIP to ' . $zipPath, 'error');
|
||||
return null;
|
||||
}
|
||||
|
||||
self::log('Bridge: downloaded MokoOnyx ZIP (' . strlen($content) . ' bytes)');
|
||||
return $zipPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch MokoOnyx's updates.xml and extract the stable channel ZIP URL.
|
||||
*
|
||||
* Always targets the stable channel — the bridge should only install
|
||||
* production-ready builds of MokoOnyx.
|
||||
*/
|
||||
private static function discoverStableUrl(): ?string
|
||||
{
|
||||
$xml = self::httpGet(self::UPDATES_XML_URL);
|
||||
if ($xml === false || strlen($xml) < 100) {
|
||||
self::log('Bridge: failed to fetch MokoOnyx updates.xml', 'warning');
|
||||
return null;
|
||||
}
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
$doc = simplexml_load_string($xml);
|
||||
libxml_clear_errors();
|
||||
|
||||
if (!$doc) {
|
||||
self::log('Bridge: failed to parse MokoOnyx updates.xml', 'warning');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the stable <update> block
|
||||
foreach ($doc->update as $update) {
|
||||
$tags = $update->tags->tag ?? [];
|
||||
foreach ($tags as $tag) {
|
||||
if ((string) $tag === 'stable') {
|
||||
foreach ($update->downloads->downloadurl as $dl) {
|
||||
$format = (string) ($dl['format'] ?? '');
|
||||
$url = trim((string) $dl);
|
||||
if ($format === 'zip' && !empty($url)) {
|
||||
self::log('Bridge: discovered stable URL: ' . $url);
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::log('Bridge: no stable ZIP URL found in MokoOnyx updates.xml', 'warning');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP GET helper — tries file_get_contents then cURL.
|
||||
*
|
||||
* @return string|false Response body or false on failure.
|
||||
*/
|
||||
private static function httpGet(string $url)
|
||||
{
|
||||
$content = false;
|
||||
|
||||
// Method 1: file_get_contents
|
||||
if (ini_get('allow_url_fopen')) {
|
||||
$ctx = stream_context_create([
|
||||
'http' => [
|
||||
@@ -106,12 +188,11 @@ class MokoBridgeMigration
|
||||
'verify_peer_name' => true,
|
||||
],
|
||||
]);
|
||||
$content = @file_get_contents(self::RELEASE_URL, false, $ctx);
|
||||
$content = @file_get_contents($url, false, $ctx);
|
||||
}
|
||||
|
||||
// Method 2: cURL
|
||||
if ($content === false && function_exists('curl_init')) {
|
||||
$ch = curl_init(self::RELEASE_URL);
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
@@ -128,18 +209,7 @@ class MokoBridgeMigration
|
||||
}
|
||||
}
|
||||
|
||||
if ($content === false || strlen($content) < 1000) {
|
||||
self::log('Bridge: failed to download MokoOnyx ZIP from ' . self::RELEASE_URL, 'error');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file_put_contents($zipPath, $content) === false) {
|
||||
self::log('Bridge: failed to write ZIP to ' . $zipPath, 'error');
|
||||
return null;
|
||||
}
|
||||
|
||||
self::log('Bridge: downloaded MokoOnyx ZIP (' . strlen($content) . ' bytes)');
|
||||
return $zipPath;
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -113,15 +113,7 @@ class Tpl_MokocassiopeiaInstallerScript
|
||||
);
|
||||
}
|
||||
|
||||
// Bridge migration: MokoCassiopeia → MokoOnyx
|
||||
$bridgeScript = __DIR__ . '/helper/bridge.php';
|
||||
if (is_file($bridgeScript)) {
|
||||
require_once $bridgeScript;
|
||||
if (class_exists('MokoBridgeMigration')) {
|
||||
MokoBridgeMigration::run();
|
||||
}
|
||||
}
|
||||
|
||||
// Bridge migration runs in postflight() — not here — to avoid double execution
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user