Author: Shivam Mathur (shivammathur) Date: 2024-11-25T04:54:17+05:30 Commit: https://github.com/php/web-downloads/commit/67eef4454300543be2fb009d2ae6d136ea8733b2 Raw diff: https://github.com/php/web-downloads/commit/67eef4454300543be2fb009d2ae6d136ea8733b2.diff
Refactor logic to move and configure files to commands Changed paths: A autoloader.php A runner.php A src/Console/Command.php A src/Console/Command/PeclCommand.php A src/Console/Command/PhpCommand.php A src/Console/Command/WinlibsCommand.php M src/GetArtifacts.php M src/PeclHandler.php M src/PhpHandler.php M src/WinlibsHandler.php Diff: diff --git a/autoloader.php b/autoloader.php new file mode 100644 index 0000000..dcafefa --- /dev/null +++ b/autoloader.php @@ -0,0 +1,18 @@ +<?php + +spl_autoload_register(function ($class) { + $prefix = 'App\\'; + $base_dir = __DIR__ . '/src/'; + + $len = strlen($prefix); + if (strncmp($prefix, $class, $len) !== 0) { + return; + } + + $relative_class = substr($class, $len); + $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; + + if (file_exists($file)) { + require $file; + } +}); \ No newline at end of file diff --git a/runner.php b/runner.php new file mode 100644 index 0000000..ca3638d --- /dev/null +++ b/runner.php @@ -0,0 +1,62 @@ +#!/usr/bin/env php +<?php + +use App\Console\Command; + +require_once __DIR__ . '/autoloader.php'; + +$consoleDirectory = __DIR__ . '/src/Console/Command'; + +function getClassname($directory, $file): string +{ + $relativePath = str_replace($directory, '', $file->getPathname()); + $relativePath = str_replace('/', '\\', $relativePath); + $relativePath = trim($relativePath, '\\'); + $className = 'App\\Console\\Command\\' . $relativePath; + return str_replace('.php', '', $className); +} + +function discoverCommands(string $directory, $argc, $argv): array +{ + $commands = []; + foreach ( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::LEAVES_ONLY + ) as $file) { + if ($file->isFile() && $file->getExtension() === 'php') { + $className = getClassName($directory, $file); + if (is_subclass_of($className, Command::class)) { + $instance = new $className($argc, $argv); + $commands[$instance->getSignature()] = $instance; + } + } + } + return $commands; +} + +function listCommands(array $commands): void +{ + echo "Available commands:\n"; + /** @var Command $command */ + foreach ($commands as $signature => $command) { + echo $signature . " - " . $command->getDescription() . "\n"; + } +} + +$commands = discoverCommands($consoleDirectory, $argc, $argv); + +$commandInput = $argv[1] ?? 'help'; + +if (in_array($commandInput, ['help', '--help', '-h', '?'], true)) { + listCommands($commands); + exit(Command::SUCCESS); +} + +if (isset($commands[$commandInput])) { + $status = $commands[$commandInput]->handle($argc, $argv); + exit($status); +} else { + echo "Command not found\n"; + exit(Command::INVALID); +} diff --git a/src/Console/Command.php b/src/Console/Command.php new file mode 100644 index 0000000..84e83d3 --- /dev/null +++ b/src/Console/Command.php @@ -0,0 +1,67 @@ +<?php + +namespace App\Console; + +abstract class Command +{ + public const SUCCESS = 0; + public const FAILURE = 1; + public const INVALID = 2; + + protected string $signature = ''; + + protected string $description = ''; + + public function __construct( + protected ?int $argc = null, + protected ?array $argv = null, + protected array $arguments = [], + protected array $options = [], + ) { + if ($argc !== null && $argv !== null) { + $this->parse($argc, $argv); + } + } + abstract public function handle(); + + + private function parse($argc, $argv): void { + $pattern = '/\{(\w+)}|\{--(\w+)}/'; + $signatureParts = []; + if (preg_match_all($pattern, $this->signature, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $signatureParts[] = $match[1] ?: $match[2]; + } + } + + $argCount = 0; + for ($i = 1; $i < $argc; $i++) { + if (preg_match('/^--([^=]+)=(.*)$/', $argv[$i], $matches)) { + $this->options[$matches[1]] = $matches[2]; + } else { + if (isset($signatureParts[$argCount])) { + $this->arguments[$signatureParts[$argCount]] = $argv[$i]; + } else { + $this->arguments[$argCount] = $argv[$i]; + } + $argCount++; + } + } + } + + public function getSignature(): string { + return explode(' ', $this->signature)[0]; + } + + public function getDescription(): string { + return $this->description; + } + + public function getArgument($index) { + return $this->arguments[$index] ?? null; + } + + public function getOption($name) { + return $this->options[$name] ?? null; + } +} \ No newline at end of file diff --git a/src/Console/Command/PeclCommand.php b/src/Console/Command/PeclCommand.php new file mode 100644 index 0000000..cd813e0 --- /dev/null +++ b/src/Console/Command/PeclCommand.php @@ -0,0 +1,65 @@ +<?php + +namespace App\Console\Command; + +use App\Console\Command; +use Exception; +use ZipArchive; + +class PeclCommand extends Command +{ + protected string $signature = 'pecl:add --base-directory='; + + protected string $description = 'Add pecl extensions'; + + public function handle(): int { + try { + $baseDirectory = $this->getOption('base-directory'); + if(!$baseDirectory) { + throw new Exception('Base directory is required'); + } + + $files = glob(getenv('BUILDS_DIRECTORY') . '/php/*.zip'); + + // We lock the files we are working on + // so that we don't process them again if the command is run again + $filteredFiles = []; + foreach ($files as $filepath) { + $lockFile = $filepath . '.lock'; + if(!file_exists($lockFile)) { + touch($lockFile); + $filteredFiles[] = $filepath; + } + } + + foreach ($filteredFiles as $filepath) { + + $destinationDirectory = $baseDirectory . "/pecl/releases"; + + if (!is_dir($destinationDirectory)) { + mkdir($destinationDirectory, 0755, true); + } + + $zip = new ZipArchive(); + + if ($zip->open($filepath) === TRUE) { + if ($zip->extractTo($destinationDirectory) === FALSE) { + throw new Exception('Failed to extract the extension build'); + } + $zip->close(); + } else { + throw new Exception('Failed to extract the extension'); + } + + unlink($filepath); + + unlink($filepath . '.lock'); + } + + return Command::SUCCESS; + } catch (Exception $e) { + echo $e->getMessage(); + return Command::FAILURE; + } + } +} \ No newline at end of file diff --git a/src/Console/Command/PhpCommand.php b/src/Console/Command/PhpCommand.php new file mode 100644 index 0000000..def12e1 --- /dev/null +++ b/src/Console/Command/PhpCommand.php @@ -0,0 +1,284 @@ +<?php + +namespace App\Console\Command; + +use App\Console\Command; +use DateTimeImmutable; +use Exception; +use ZipArchive; + +class PhpCommand extends Command +{ + protected string $signature = 'php:add --base-directory='; + protected string $description = 'Add php builds'; + + protected ?string $baseDirectory = null; + + public function handle(): int { + try { + $this->baseDirectory = $this->getOption('base-directory'); + if(!$this->baseDirectory) { + throw new Exception('Base directory is required'); + } + + $files = glob(getenv('BUILDS_DIRECTORY') . '/php/*.zip'); + + // We lock the files we are working on + // so that we don't process them again if the command is run again + $filteredFiles = []; + foreach ($files as $filepath) { + $lockFile = $filepath . '.lock'; + if(!file_exists($lockFile)) { + touch($lockFile); + $filteredFiles[] = $filepath; + } + } + + foreach ($filteredFiles as $filepath) { + $hash = hash('sha256', $filepath) . strtotime('now'); + $tempDirectory = "/tmp/php-" . $hash; + + if(is_dir($tempDirectory)) { + rmdir($tempDirectory); + } + mkdir($tempDirectory, 0755, true); + + $zip = new ZipArchive(); + + if ($zip->open($filepath) === TRUE) { + if($zip->extractTo($tempDirectory) === FALSE) { + throw new Exception('Failed to extract the extension build'); + } + $zip->close(); + } else { + throw new Exception('Failed to extract the extension'); + } + + unlink($filepath); + + $destinationDirectory = $this->getDestinationDirectory($tempDirectory); + + $this->moveBuild($tempDirectory, $destinationDirectory); + + $this->generateListing($destinationDirectory); + + rmdir($tempDirectory); + + unlink($filepath . '.lock'); + } + return Command::SUCCESS; + } catch (Exception $e) { + echo $e->getMessage(); + return Command::FAILURE; + } + } + + private function getDestinationDirectory(string $tempDirectory): string + { + $testPackFile = basename(glob($tempDirectory . '/php-test-pack-*.zip')[0]); + $testPackFileName = str_replace('.zip', '', $testPackFile); + $version = explode('-', $testPackFileName)[3]; + return $this->baseDirectory . (preg_match('/^\d+\.\d+\.\d+$/', $version) ? '/releases' : '/qa'); + } + + /** + * @throws Exception + */ + private function moveBuild(string $tempDirectory, string $destinationDirectory): void + { + $files = glob($tempDirectory . '/*'); + if($files) { + $version = $this->getFileVersion($files[0]); + foreach ($files as $file) { + $fileName = basename($file); + $destination = $destinationDirectory . '/' . $fileName; + rename($file, $destination); + } + rmdir($tempDirectory); + $this->copyBuildsToArchive($destinationDirectory, $version); + } else { + throw new Exception('No builds found in the artifact'); + } + } + + private function copyBuildsToArchive(string $directory, string $version): void + { + $version_short = substr($version, 0, 3); + $files = glob($directory . '/php*-' . $version_short . '-*.zip'); + foreach ($files as $file) { + $fileVersion = $this->getFileVersion($file); + if($fileVersion) { + copy($directory . '/' . basename($file), $directory . '/archive/' . $file); + if(version_compare($fileVersion, $version) < 0) { + unlink($file); + } + } + } + } + + private function getFileVersion(string $file): string + { + $file = preg_replace('/^php-((debug|devel|test)-pack)?/', '', $file); + return explode('-', $file)[0]; + } + + /** + * @throws Exception + */ + private function generateListing(string $directory): void + { + $builds = glob($directory . '/php-[678].*[0-9]-latest.zip'); + if (empty($builds)) { + $builds = glob($directory . '/php-[678].*[0-9].zip'); + } + + $releases = []; + $sha256sums = $this->getSha256Sums($directory); + foreach ($builds as $file) { + $file_ori = $file; + $mtime = date('Y-M-d H:i:s', filemtime($file)); + + $parts = $this->parseFileName(basename($file)); + $key = ($parts['nts'] ? 'nts-' : 'ts-') . $parts['vc'] . '-' . $parts['arch']; + $version_short = $parts['version_short']; + if (!isset($releases['version'])) { + $releases[$version_short]['version'] = $parts['version']; + } + $releases[$version_short][$key]['mtime'] = $mtime; + $releases[$version_short][$key]['zip'] = [ + 'path' => $file_ori, + 'size' => $this->bytes2string(filesize($file_ori)), + 'sha256' => $sha256sums[strtolower($file_ori)] + ]; + $namingPattern = $parts['version'] . ($parts['nts'] ? '-' . $parts['nts'] : '') . '-Win32-' . $parts['vc'] . '-' . $parts['arch'] . ($parts['ts'] ? '-' . $parts['ts'] : ''); + $build_types = [ + 'source' => 'php-' . $parts['version'] . '-src.zip', + 'debug_pack' => 'php-debug-pack-' . $namingPattern . '.zip', + 'devel_pack' => 'php-devel-pack-' . $namingPattern . '.zip', + 'installer' => 'php-' . $namingPattern . '.msi', + 'test_pack' => 'php-test-pack-' . $parts['version'] . '.zip', + ]; + foreach($build_types as $type => $fileName) { + $filePath = $directory . '/' . $fileName; + if (file_exists($filePath)) { + $releases[$version_short][$type] = [ + 'path' => $fileName, + 'size' => $this->bytes2string(filesize($filePath)) + ]; + } + } + } + + $this->updateReleasesJson($releases, $directory); + if($directory === $this->baseDirectory . '/releases') { + $this->updateLatestBuilds($releases, $directory); + } + } + + /** + * @throws Exception + */ + private function updateReleasesJson(array $releases, string $directory): void + { + foreach ($releases as &$release) { + foreach ($release as &$build_type) { + if (! is_array($build_type) || ! isset($build_type['mtime'])) { + continue; + } + + try { + $date = new DateTimeImmutable($build_type['mtime']); + $build_type['mtime'] = $date->format('c'); + } catch (Exception $exception) { + throw new Exception('Failed to generate releases.json: ' . $exception->getMessage()); + } + } + unset($build_type); + } + unset($release); + + file_put_contents( + $directory . '/releases.json', + json_encode($releases, JSON_PRETTY_PRINT) + ); + } + + private function updateLatestBuilds($releases, $directory): void + { + foreach ($releases as $versionShort => $release) { + $latestFileName = str_replace($release['version'], $versionShort, $release['path']); + $latestFileName = str_replace('.zip', '-latest.zip', $latestFileName); + copy($directory . '/' . $release['path'], $directory . '/latest/' . $latestFileName); + } + } + + private function getSha256Sums($directory): array + { + $result = []; + $sha_file = fopen("$directory/sha256sum.txt", 'w'); + foreach (scandir($directory) as $filename) { + if (pathinfo($filename, PATHINFO_EXTENSION) !== 'zip') { + continue; + } + $sha256 = hash_file('sha256', "$directory/$filename"); + fwrite($sha_file, "$sha256 *$filename\n"); + $result[strtolower(basename($filename))] = $sha256; + } + fclose($sha_file); + return $result; + } + + private function bytes2string(int $size): float + { + $sizes = ['YB', 'ZB', 'EB', 'PB', 'TB', 'GB', 'MB', 'kB', 'B']; + + $total = count($sizes); + + while($total-- && $size > 1024) $size /= 1024; + + return round($size, 2) . $sizes[$total]; + } + + private function parseFileName($fileName): array + { + $fileName = str_replace(['-Win32', '.zip'], ['', ''], $fileName); + + $parts = explode('-', $fileName); + if (is_numeric($parts[2]) || $parts[2] == 'dev') { + $version = $parts[1] . '-' . $parts[2]; + $nts = $parts[3] == 'nts' ? 'nts' : false; + if ($nts) { + $vc = $parts[4]; + $arch = $parts[5]; + } else { + $vc = $parts[3]; + $arch = $parts[4]; + } + } elseif ($parts[2] == 'nts') { + $nts = 'nts'; + $version = $parts[1]; + $vc = $parts[3]; + $arch = $parts[4]; + } else { + $nts = false; + $version = $parts[1]; + $vc = $parts[2]; + $arch = $parts[3]; + } + if (is_numeric($vc)) { + $vc = 'VC6'; + $arch = 'x86'; + } + $t = count($parts) - 1; + $ts = is_numeric($parts[$t]) ? $parts[$t] : false; + + return [ + 'version' => $version, + 'version_short' => substr($version, 0, 3), + 'nts' => $nts, + 'vc' => $vc, + 'arch' => $arch, + 'ts' => $ts + ]; + } +} \ No newline at end of file diff --git a/src/Console/Command/WinlibsCommand.php b/src/Console/Command/WinlibsCommand.php new file mode 100644 index 0000000..b0bbcb9 --- /dev/null +++ b/src/Console/Command/WinlibsCommand.php @@ -0,0 +1,118 @@ +<?php + +namespace App\Console\Command; + +use App\Console\Command; +use Exception; + +class WinlibsCommand extends Command +{ + protected string $signature = 'winlibs:add --base-directory='; + protected string $description = 'Add winlibs dependencies'; + + protected ?string $baseDirectory = null; + + public function handle(): int { + try { + $this->baseDirectory = $this->getOption('base-directory'); + if(!$this->baseDirectory) { + throw new Exception('Base directory is required'); + } + + $buildDirectories = glob($this->baseDirectory . '/winlibs/*', GLOB_ONLYDIR); + + // We lock the Directories we are working on + // so that we don't process them again if the command is run again + $filteredDirectories = []; + foreach ($buildDirectories as $directoryPath) { + $lockFile = $directoryPath . '.lock'; + if(!file_exists($lockFile)) { + touch($lockFile); + $filteredDirectories[] = $directoryPath; + } + } + + foreach($filteredDirectories as $directoryPath) { + $data = json_decode(file_get_contents($directoryPath . '/data.json'), true); + extract($data); + $files = glob($directoryPath . '/*.zip'); + $files = $this->parseFiles($files); + if($files) { + $this->copyFiles($files, $library, $ref, $vs_version_targets); + $this->updateSeriesFiles($files, $library, $ref, $php_versions, $vs_version_targets, $stability); + } + + rmdir($directoryPath); + + unlink($directoryPath . '.lock'); + } + return Command::SUCCESS; + } catch (Exception $e) { + echo $e->getMessage(); + return Command::FAILURE; + } + } + + private function parseFiles(array $files): array + { + $data = []; + foreach ($files as $file) { + $fileName = basename($file); + $fileNameParts = explode('.', $fileName); + $parsedFileNameParts = explode('-', $fileNameParts[0]); + $data[] = [ + 'file_path' => $file, + 'file_name' => $fileName, + 'extension' => $fileNameParts[1], + 'artifact_name' => $parsedFileNameParts[0], + 'vs_version' => $parsedFileNameParts[1], + 'arch' => $parsedFileNameParts[2], + ]; + } + return $data; + } + + private function copyFiles(array $files, $library, $ref, $vs_version_targets): void + { + $baseDirectory = $this->baseDirectory . "/php-sdk/deps"; + if(!is_dir($baseDirectory)) { + mkdir($baseDirectory, 0755, true); + } + $vs_version_targets = explode(',', $vs_version_targets); + foreach($files as $file) { + foreach ($vs_version_targets as $vs_version_target) { + $destinationDirectory = $baseDirectory . '/' . $vs_version_target . '/' . $file['arch']; + $destinationFileName = str_replace($file['artifact_name'], $library . '-' . $ref, $file['file_name']); + copy($file['file_path'], $destinationDirectory . '/' . $destinationFileName); + } + } + } + + private function updateSeriesFiles($files, $library, $ref, $php_versions, $vs_version_targets, $stability): void + { + $php_versions = explode(',', $php_versions); + $vs_version_targets = explode(',', $vs_version_targets); + $stability_values = explode(',', $stability); + + $baseDirectory = $this->baseDirectory . "/php-sdk/deps/series"; + + foreach ($php_versions as $php_version) { + foreach ($vs_version_targets as $vs_version_target) { + foreach ($stability_values as $stability_value) { + foreach ($files as $file) { + $fileName = str_replace($file['artifact_name'], $library . '-' . $ref, $file['file_name']); + $arch = $file['arch']; + $seriesFile = $baseDirectory . "/packages-$php_version-$vs_version_target-$arch-$stability_value.txt"; + $file_lines = file($seriesFile, FILE_IGNORE_NEW_LINES); + foreach($file_lines as $no => $line) { + if(str_starts_with($line, $library)) { + $file_lines[$no] = $fileName; + } + } + file_put_contents($seriesFile, implode("\n", $file_lines)); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/GetArtifacts.php b/src/GetArtifacts.php index 2a18046..7a38e2d 100644 --- a/src/GetArtifacts.php +++ b/src/GetArtifacts.php @@ -4,7 +4,7 @@ class GetArtifacts { - public static function handle($workflow_run_id, $token): null|array + public static function handle($workflow_run_id, $token): void { $ch = curl_init(); @@ -29,16 +29,17 @@ public static function handle($workflow_run_id, $token): null|array if ($err) { echo "cURL Error #:" . $err; - return null; } else { - $files = []; $artifacts = json_decode($response, true); + $workflowRunDirectory = getenv('BUILDS_DIRECTORY') . "/winlibs/" . $workflow_run_id; + if (is_dir($workflowRunDirectory)) { + rmdir($workflowRunDirectory); + } + mkdir($workflowRunDirectory, 0755, true); foreach ($artifacts['artifacts'] as $artifact) { - $filepath = "/tmp/" . $artifact['name'] . ".zip"; - $files[] = $filepath; + $filepath = $workflowRunDirectory . "/" . $artifact['name'] . ".zip"; FetchArtifact::handle($artifact['archive_download_url'], $filepath, $token); } - return $files; } } diff --git a/src/PeclHandler.php b/src/PeclHandler.php index 4329f45..abba598 100644 --- a/src/PeclHandler.php +++ b/src/PeclHandler.php @@ -43,31 +43,12 @@ protected function execute(array $data): void */ private function fetchExtension(string $extension, string $ref, string $url, string $token): void { - $filepath = "/tmp/$extension-$ref-" . hash('sha256', $url) . strtotime('now') . ".zip"; + $filepath = getenv('BUILDS_DIRECTORY') . "/pecl/$extension-$ref-" . hash('sha256', $url) . strtotime('now') . ".zip"; FetchArtifact::handle($url, $filepath, $token); if(!file_exists($filepath) || mime_content_type($filepath) !== 'application/zip') { throw new Exception('Failed to fetch the extension'); } - - $destinationDirectory = getenv('BUILDS_DIRECTORY') . "/pecl/releases"; - - if(!is_dir($destinationDirectory)) { - mkdir($destinationDirectory, 0755, true); - } - - $zip = new ZipArchive(); - - if ($zip->open($filepath) === TRUE) { - if($zip->extractTo($destinationDirectory) === FALSE) { - throw new Exception('Failed to extract the extension build'); - } - $zip->close(); - } else { - throw new Exception('Failed to extract the extension'); - } - - unlink($filepath); } } \ No newline at end of file diff --git a/src/PhpHandler.php b/src/PhpHandler.php index 7c9a1d0..e3425e5 100644 --- a/src/PhpHandler.php +++ b/src/PhpHandler.php @@ -45,247 +45,12 @@ private function fetchPhpBuild(string $url, string $token): void { $hash = hash('sha256', $url) . strtotime('now'); - $filepath = "/tmp/php-" . $hash . ".tar.gz"; + $filepath = getenv('BUILDS_DIRECTORY') . "/php/php-" . $hash . ".tar.gz"; FetchArtifact::handle($url, $filepath, $token); if(!file_exists($filepath) || mime_content_type($filepath) !== 'application/zip') { throw new Exception('Failed to fetch the PHP build'); } - - $tempDirectory = "/tmp/php-" . $hash; - - if(is_dir($tempDirectory)) { - rmdir($tempDirectory); - } - mkdir($tempDirectory, 0755, true); - - $zip = new ZipArchive(); - - if ($zip->open($filepath) === TRUE) { - if($zip->extractTo($tempDirectory) === FALSE) { - throw new Exception('Failed to extract the extension build'); - } - $zip->close(); - } else { - throw new Exception('Failed to extract the extension'); - } - - unlink($filepath); - - $destinationDirectory = $this->getDestinationDirectory($tempDirectory); - - $this->moveBuild($tempDirectory, $destinationDirectory); - - $this->generateListing($destinationDirectory); - } - - private function getDestinationDirectory(string $tempDirectory): string - { - $testPackFile = basename(glob($tempDirectory . '/php-test-pack-*.zip')[0]); - $testPackFileName = str_replace('.zip', '', $testPackFile); - $version = explode('-', $testPackFileName)[3]; - return getenv('BUILDS_DIRECTORY') . (preg_match('/^\d+\.\d+\.\d+$/', $version) ? '/releases' : '/qa'); - } - - /** - * @throws Exception - */ - private function moveBuild(string $tempDirectory, string $destinationDirectory): void - { - $files = glob($tempDirectory . '/*'); - if($files) { - $version = $this->getFileVersion($files[0]); - foreach ($files as $file) { - $fileName = basename($file); - $destination = $destinationDirectory . '/' . $fileName; - rename($file, $destination); - } - rmdir($tempDirectory); - $this->copyBuildsToArchive($destinationDirectory, $version); - } else { - throw new Exception('No builds found in the artifact'); - } - } - - private function copyBuildsToArchive(string $directory, string $version): void - { - $version_short = substr($version, 0, 3); - $files = glob($directory . '/php*-' . $version_short . '-*.zip'); - foreach ($files as $file) { - $fileVersion = $this->getFileVersion($file); - if($fileVersion) { - copy($directory . '/' . basename($file), $directory . '/archive/' . $file); - if(version_compare($fileVersion, $version) < 0) { - unlink($file); - } - } - } - } - - private function getFileVersion(string $file): string - { - $file = preg_replace('/^php-((debug|devel|test)-pack)?/', '', $file); - return explode('-', $file)[0]; - } - - /** - * @throws Exception - */ - private function generateListing(string $directory): void - { - $builds = glob($directory . '/php-[678].*[0-9]-latest.zip'); - if (empty($builds)) { - $builds = glob($directory . '/php-[678].*[0-9].zip'); - } - - $releases = []; - $sha256sums = $this->getSha256Sums($directory); - foreach ($builds as $file) { - $file_ori = $file; - $mtime = date('Y-M-d H:i:s', filemtime($file)); - - $parts = $this->parseFileName(basename($file)); - $key = ($parts['nts'] ? 'nts-' : 'ts-') . $parts['vc'] . '-' . $parts['arch']; - $version_short = $parts['version_short']; - if (!isset($releases['version'])) { - $releases[$version_short]['version'] = $parts['version']; - } - $releases[$version_short][$key]['mtime'] = $mtime; - $releases[$version_short][$key]['zip'] = [ - 'path' => $file_ori, - 'size' => $this->bytes2string(filesize($file_ori)), - 'sha256' => $sha256sums[strtolower($file_ori)] - ]; - $namingPattern = $parts['version'] . ($parts['nts'] ? '-' . $parts['nts'] : '') . '-Win32-' . $parts['vc'] . '-' . $parts['arch'] . ($parts['ts'] ? '-' . $parts['ts'] : ''); - $build_types = [ - 'source' => 'php-' . $parts['version'] . '-src.zip', - 'debug_pack' => 'php-debug-pack-' . $namingPattern . '.zip', - 'devel_pack' => 'php-devel-pack-' . $namingPattern . '.zip', - 'installer' => 'php-' . $namingPattern . '.msi', - 'test_pack' => 'php-test-pack-' . $parts['version'] . '.zip', - ]; - foreach($build_types as $type => $fileName) { - $filePath = $directory . '/' . $fileName; - if (file_exists($filePath)) { - $releases[$version_short][$type] = [ - 'path' => $fileName, - 'size' => $this->bytes2string(filesize($filePath)) - ]; - } - } - } - - $this->updateReleasesJson($releases, $directory); - if($directory === getenv('BUILDS_DIRECTORY') . '/releases') { - $this->updateLatestBuilds($releases, $directory); - } - } - - /** - * @throws Exception - */ - private function updateReleasesJson(array $releases, string $directory): void - { - foreach ($releases as &$release) { - foreach ($release as &$build_type) { - if (! is_array($build_type) || ! isset($build_type['mtime'])) { - continue; - } - - try { - $date = new DateTimeImmutable($build_type['mtime']); - $build_type['mtime'] = $date->format('c'); - } catch (Exception $exception) { - throw new Exception('Failed to generate releases.json: ' . $exception->getMessage()); - } - } - unset($build_type); - } - unset($release); - - file_put_contents( - $directory . '/releases.json', - json_encode($releases, JSON_PRETTY_PRINT) - ); - } - - private function updateLatestBuilds($releases, $directory): void - { - foreach ($releases as $versionShort => $release) { - $latestFileName = str_replace($release['version'], $versionShort, $release['path']); - $latestFileName = str_replace('.zip', '-latest.zip', $latestFileName); - copy($directory . '/' . $release['path'], $directory . '/latest/' . $latestFileName); - } - } - - private function getSha256Sums($directory): array - { - $result = []; - $sha_file = fopen("$directory/sha256sum.txt", 'w'); - foreach (scandir($directory) as $filename) { - if (pathinfo($filename, PATHINFO_EXTENSION) !== 'zip') { - continue; - } - $sha256 = hash_file('sha256', "$directory/$filename"); - fwrite($sha_file, "$sha256 *$filename\n"); - $result[strtolower(basename($filename))] = $sha256; - } - fclose($sha_file); - return $result; - } - - private function bytes2string(int $size): float - { - $sizes = ['YB', 'ZB', 'EB', 'PB', 'TB', 'GB', 'MB', 'kB', 'B']; - - $total = count($sizes); - - while($total-- && $size > 1024) $size /= 1024; - - return round($size, 2) . $sizes[$total]; - } - - private function parseFileName($fileName): array - { - $fileName = str_replace(['-Win32', '.zip'], ['', ''], $fileName); - - $parts = explode('-', $fileName); - if (is_numeric($parts[2]) || $parts[2] == 'dev') { - $version = $parts[1] . '-' . $parts[2]; - $nts = $parts[3] == 'nts' ? 'nts' : false; - if ($nts) { - $vc = $parts[4]; - $arch = $parts[5]; - } else { - $vc = $parts[3]; - $arch = $parts[4]; - } - } elseif ($parts[2] == 'nts') { - $nts = 'nts'; - $version = $parts[1]; - $vc = $parts[3]; - $arch = $parts[4]; - } else { - $nts = false; - $version = $parts[1]; - $vc = $parts[2]; - $arch = $parts[3]; - } - if (is_numeric($vc)) { - $vc = 'VC6'; - $arch = 'x86'; - } - $t = count($parts) - 1; - $ts = is_numeric($parts[$t]) ? $parts[$t] : false; - - return [ - 'version' => $version, - 'version_short' => substr($version, 0, 3), - 'nts' => $nts, - 'vc' => $vc, - 'arch' => $arch, - 'ts' => $ts - ]; } } \ No newline at end of file diff --git a/src/WinlibsHandler.php b/src/WinlibsHandler.php index 4625c10..f123d82 100644 --- a/src/WinlibsHandler.php +++ b/src/WinlibsHandler.php @@ -32,74 +32,8 @@ protected function validate(array $data): bool protected function execute(array $data): void { extract($data); - $files = GetArtifacts::handle($workflow_run_id, $token); - $files = $this->parseFiles($files); - if($files) { - $this->copyFiles($files, $library, $ref, $vs_version_targets); - $this->updateSeriesFiles($files, $library, $ref, $php_versions, $vs_version_targets, $stability); - } - } - - private function parseFiles(array $files): array - { - $data = []; - foreach ($files as $file) { - $fileName = basename($file); - $fileNameParts = explode('.', $fileName); - $parsedFileNameParts = explode('-', $fileNameParts[0]); - $data[] = [ - 'file_path' => $file, - 'file_name' => $fileName, - 'extension' => $fileNameParts[1], - 'artifact_name' => $parsedFileNameParts[0], - 'vs_version' => $parsedFileNameParts[1], - 'arch' => $parsedFileNameParts[2], - ]; - } - return $data; - } - - private function copyFiles(array $files, $library, $ref, $vs_version_targets): void - { - $baseDirectory = getenv('BUILDS_DIRECTORY') . "/php-sdk/deps"; - if(!is_dir($baseDirectory)) { - mkdir($baseDirectory, 0755, true); - } - $vs_version_targets = explode(',', $vs_version_targets); - foreach($files as $file) { - foreach ($vs_version_targets as $vs_version_target) { - $destinationDirectory = $baseDirectory . '/' . $vs_version_target . '/' . $file['arch']; - $destinationFileName = str_replace($file['artifact_name'], $library . '-' . $ref, $file['file_name']); - copy($file['file_path'], $destinationDirectory . '/' . $destinationFileName); - } - } - } - - private function updateSeriesFiles($files, $library, $ref, $php_versions, $vs_version_targets, $stability): void - { - $php_versions = explode(',', $php_versions); - $vs_version_targets = explode(',', $vs_version_targets); - $stability_values = explode(',', $stability); - - $baseDirectory = getenv('BUILDS_DIRECTORY') . "/php-sdk/deps/series"; - - foreach ($php_versions as $php_version) { - foreach ($vs_version_targets as $vs_version_target) { - foreach ($stability_values as $stability_value) { - foreach ($files as $file) { - $fileName = str_replace($file['artifact_name'], $library . '-' . $ref, $file['file_name']); - $arch = $file['arch']; - $seriesFile = $baseDirectory . "/packages-$php_version-$vs_version_target-$arch-$stability_value.txt"; - $file_lines = file($seriesFile, FILE_IGNORE_NEW_LINES); - foreach($file_lines as $no => $line) { - if(strpos($line, $library) === 0) { - $file_lines[$no] = $fileName; - } - } - file_put_contents($seriesFile, implode("\n", $file_lines)); - } - } - } - } + GetArtifacts::handle($workflow_run_id, $token); + $directory = getenv('BUILDS_DIRECTORY') . '/winlibs/'. $workflow_run_id; + file_put_contents( $directory . '/data.json', json_encode($data)); } } \ No newline at end of file