From 8e30fa54b3c2f945e856e0e5a371f49a7b3556ee Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Fri, 26 Jun 2026 19:26:54 -0500 Subject: [PATCH] feat: support nested Joomla packages in release_package.php When a sub-package directory contains its own pkg_*.xml manifest and packages/ directory (e.g. a git submodule), recursively build each sub-extension into ZIPs before assembling the outer package ZIP. --- cli/release_package.php | 56 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/cli/release_package.php b/cli/release_package.php index c5f83f4..fa0dc5d 100644 --- a/cli/release_package.php +++ b/cli/release_package.php @@ -270,12 +270,66 @@ class ReleasePackageCli extends CliFramework } } + // Check if sub-source is itself a Joomla package (nested package) + $nestedPkgManifests = glob("{$subSourceDir}/pkg_*.xml") ?: []; + $isNestedPackage = !empty($nestedPkgManifests) && is_dir("{$subSourceDir}/packages"); + $subZip = new \ZipArchive(); if ($subZip->open($subZipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) { $this->log('ERROR', "Failed to create sub-package ZIP: {$subZipPath}"); continue; } - $this->addDirToZip($subZip, $subSourceDir, '', $this->excludePatterns); + + if ($isNestedPackage) { + // Build nested package: zip each sub-extension, then assemble + echo " Building nested package: {$subName}\n"; + $nestedPkgDirs = glob("{$subSourceDir}/packages/*", GLOB_ONLYDIR) ?: []; + + // Read nested manifest to filter only listed sub-extensions + $nestedManifested = []; + foreach ($nestedPkgManifests as $npmf) { + $npmXml = @simplexml_load_file($npmf); + if ($npmXml && isset($npmXml->files)) { + foreach ($npmXml->files->file as $fn) { + $nzn = pathinfo((string) $fn, PATHINFO_FILENAME); + if (!empty($nzn)) { + $nestedManifested[$nzn] = true; + } + } + } + } + + foreach ($nestedPkgDirs as $npd) { + $nestedSubName = basename($npd); + if (!empty($nestedManifested) && !isset($nestedManifested[$nestedSubName])) { + continue; + } + $nestedSubZipPath = "{$outputDir}/{$nestedSubName}.zip"; + $nsZip = new \ZipArchive(); + if ($nsZip->open($nestedSubZipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) { + continue; + } + $this->addDirToZip($nsZip, $npd, '', $this->excludePatterns); + $nsZip->close(); + $subZip->addFile($nestedSubZipPath, "packages/{$nestedSubName}.zip"); + echo " Nested sub: {$nestedSubName}.zip\n"; + } + + // Add top-level files (manifest, script, language) + $nestedTopFiles = array_merge( + glob("{$subSourceDir}/*.xml") ?: [], + glob("{$subSourceDir}/*.php") ?: [] + ); + foreach ($nestedTopFiles as $ntf) { + $subZip->addFile($ntf, basename($ntf)); + } + $nestedLangDir = "{$subSourceDir}/language"; + if (is_dir($nestedLangDir)) { + $this->addDirToZip($subZip, $nestedLangDir, 'language', $this->excludePatterns); + } + } else { + $this->addDirToZip($subZip, $subSourceDir, '', $this->excludePatterns); + } $subZip->close(); $zip->addFile($subZipPath, "packages/{$subName}.zip");