From 2fba61e9bd9ce41ede56c3f2cc2a35e917bdd796 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 11 Aug 2025 10:48:48 +0800 Subject: [PATCH 01/14] Enhance exception handling by binding builder and extra info to ExceptionHandler --- src/SPC/builder/BuilderBase.php | 3 + src/SPC/builder/BuilderProvider.php | 5 + src/SPC/command/BuildPHPCommand.php | 7 +- src/SPC/exception/ExceptionHandler.php | 128 ++++++++++++++++--------- src/SPC/exception/SPCException.php | 41 +++----- 5 files changed, 111 insertions(+), 73 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 1aa30f28..693c4dfd 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -229,6 +229,9 @@ abstract class BuilderBase */ abstract public function testPHP(int $build_target = BUILD_TARGET_NONE); + /** + * Build shared extensions. + */ public function buildSharedExts(): void { $lines = file(BUILD_BIN_PATH . '/php-config'); diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index d9062d06..6fbec300 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -8,6 +8,7 @@ use SPC\builder\freebsd\BSDBuilder; use SPC\builder\linux\LinuxBuilder; use SPC\builder\macos\MacOSBuilder; use SPC\builder\windows\WindowsBuilder; +use SPC\exception\ExceptionHandler; use SPC\exception\WrongUsageException; use Symfony\Component\Console\Input\InputInterface; @@ -29,6 +30,10 @@ class BuilderProvider 'BSD' => new BSDBuilder($input->getOptions()), default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'), }; + + // bind the builder to ExceptionHandler + ExceptionHandler::$bind_builder = self::$builder; + return self::$builder; } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index c987f174..5f57653d 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace SPC\command; use SPC\builder\BuilderProvider; -use SPC\exception\SPCException; +use SPC\exception\ExceptionHandler; use SPC\store\Config; use SPC\store\FileSystem; use SPC\store\SourcePatcher; @@ -165,8 +165,9 @@ class BuildPHPCommand extends BuildCommand } $this->printFormatInfo($this->getDefinedEnvs(), true); $this->printFormatInfo($indent_texts); - // bind extra info to SPCException - SPCException::bindBuildPHPExtraInfo($indent_texts); + + // bind extra info to exception handler + ExceptionHandler::$bind_build_php_extra_info = $indent_texts; logger()->notice('Build will start after 2s ...'); sleep(2); diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 3bd3fe5d..d41b3f08 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\exception; +use SPC\builder\BuilderBase; use ZM\Logger\ConsoleColor; class ExceptionHandler @@ -26,21 +27,27 @@ class ExceptionHandler WrongUsageException::class, ]; + /** @var null|BuilderBase Builder binding */ + public static ?BuilderBase $bind_builder = null; + + /** @var array Build PHP extra info binding */ + public static array $bind_build_php_extra_info = []; + public static function handleSPCException(SPCException $e): void { // XXX error: yyy $head_msg = match ($class = get_class($e)) { - BuildFailureException::class => "Build failed: {$e->getMessage()}", - DownloaderException::class => "Download failed: {$e->getMessage()}", - EnvironmentException::class => "Environment check failed: {$e->getMessage()}", - ExecutionException::class => "Command execution failed: {$e->getMessage()}", - FileSystemException::class => "File system error: {$e->getMessage()}", + BuildFailureException::class => "✗ Build failed: {$e->getMessage()}", + DownloaderException::class => "✗ Download failed: {$e->getMessage()}", + EnvironmentException::class => "⚠ Environment check failed: {$e->getMessage()}", + ExecutionException::class => "✗ Command execution failed: {$e->getMessage()}", + FileSystemException::class => "✗ File system error: {$e->getMessage()}", InterruptException::class => "⚠ Build interrupted by user: {$e->getMessage()}", - PatchException::class => "Patch apply failed: {$e->getMessage()}", - SPCInternalException::class => "SPC internal error: {$e->getMessage()}", - ValidationException::class => "Validation failed: {$e->getMessage()}", + PatchException::class => "✗ Patch apply failed: {$e->getMessage()}", + SPCInternalException::class => "✗ SPC internal error: {$e->getMessage()}", + ValidationException::class => "⚠ Validation failed: {$e->getMessage()}", WrongUsageException::class => $e->getMessage(), - default => "Unknown SPC exception {$class}: {$e->getMessage()}", + default => "✗Unknown SPC exception {$class}: {$e->getMessage()}", }; self::logError($head_msg); @@ -55,24 +62,24 @@ class ExceptionHandler // get the SPCException module if ($php_info = $e->getBuildPHPInfo()) { - self::logError('✗ Failed module: ' . ConsoleColor::yellow("PHP builder {$php_info['builder_class']} for {$php_info['os']}")); + self::logError('Failed module: ' . ConsoleColor::yellow("Builder for {$php_info['os']}")); } elseif ($lib_info = $e->getLibraryInfo()) { - self::logError('✗ Failed module: ' . ConsoleColor::yellow("library {$lib_info['library_name']} builder for {$lib_info['os']}")); + self::logError('Failed module: ' . ConsoleColor::yellow("library {$lib_info['library_name']} builder for {$lib_info['os']}")); } elseif ($ext_info = $e->getExtensionInfo()) { - self::logError('✗ Failed module: ' . ConsoleColor::yellow("shared extension {$ext_info['extension_name']} builder")); + self::logError('Failed module: ' . ConsoleColor::yellow("shared extension {$ext_info['extension_name']} builder")); } elseif (!in_array($class, self::KNOWN_EXCEPTIONS)) { - self::logError('✗ Failed From: ' . ConsoleColor::yellow('Unknown SPC module ' . $class)); + self::logError('Failed From: ' . ConsoleColor::yellow('Unknown SPC module ' . $class)); } - self::logError(''); // get command execution info if ($e instanceof ExecutionException) { - self::logError('✗ Failed command: ' . ConsoleColor::yellow($e->getExecutionCommand())); + self::logError(''); + self::logError('Failed command: ' . ConsoleColor::yellow($e->getExecutionCommand())); if ($cd = $e->getCd()) { - self::logError('✗ Command executed in: ' . ConsoleColor::yellow($cd)); + self::logError('Command executed in: ' . ConsoleColor::yellow($cd)); } if ($env = $e->getEnv()) { - self::logError('✗ Command inline env variables:'); + self::logError('Command inline env variables:'); foreach ($env as $k => $v) { self::logError(ConsoleColor::yellow("{$k}={$v}"), 4); } @@ -81,46 +88,42 @@ class ExceptionHandler // validation error if ($e instanceof ValidationException) { - self::logError('✗ Failed validation module: ' . ConsoleColor::yellow($e->getValidationModuleString())); + self::logError('Failed validation module: ' . ConsoleColor::yellow($e->getValidationModuleString())); } // environment error if ($e instanceof EnvironmentException) { - self::logError('✗ Failed environment check: ' . ConsoleColor::yellow($e->getMessage())); + self::logError('Failed environment check: ' . ConsoleColor::yellow($e->getMessage())); if (($solution = $e->getSolution()) !== null) { - self::logError('✗ Solution: ' . ConsoleColor::yellow($solution)); + self::logError('Solution: ' . ConsoleColor::yellow($solution)); } } // get patch info if ($e instanceof PatchException) { - self::logError("✗ Failed patch module: {$e->getPatchModule()}"); + self::logError("Failed patch module: {$e->getPatchModule()}"); } // get internal trace if ($e instanceof SPCInternalException) { - self::logError('✗ Internal trace:'); + self::logError('Internal trace:'); self::logError(ConsoleColor::gray("{$e->getTraceAsString()}\n"), 4); } // get the full build info if possible - if (($info = $e->getBuildPHPExtraInfo()) && defined('DEBUG_MODE')) { - self::logError('✗ Build PHP extra info:'); - $maxlen = 0; - foreach ($info as $k => $v) { - $maxlen = max(strlen($k), $maxlen); - } - foreach ($info as $k => $v) { - if (is_string($v)) { - self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow($v), 4); - } elseif (is_array($v) && !is_assoc_array($v)) { - $first = array_shift($v); - self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow($first), 4); - foreach ($v as $vs) { - self::logError(str_pad('', $maxlen + 2) . ConsoleColor::yellow($vs), 4); - } - } - } + if ($info = ExceptionHandler::$bind_build_php_extra_info) { + self::logError('', output_log: defined('DEBUG_MODE')); + self::logError('Build PHP extra info:', output_log: defined('DEBUG_MODE')); + self::printArrayInfo($info); + } + + // get the full builder options if possible + if (self::$bind_builder && $e->getBuildPHPInfo()) { + $info = $e->getBuildPHPInfo(); + self::logError('', output_log: defined('DEBUG_MODE')); + self::logError('Builder function: ' . ConsoleColor::yellow($info['builder_function']), output_log: defined('DEBUG_MODE')); + self::logError('Builder options:', output_log: defined('DEBUG_MODE')); + self::printArrayInfo(self::$bind_builder->getOptions()); } self::logError("\n----------------------------------------\n"); @@ -142,20 +145,57 @@ class ExceptionHandler public static function handleDefaultException(\Throwable $e): void { $class = get_class($e); - self::logError("Unhandled exception {$class}: {$e->getMessage()}\n\t{$e->getMessage()}\n"); + self::logError("✗ Unhandled exception {$class}:\n\t{$e->getMessage()}\n"); self::logError('Stack trace:'); - self::logError(ConsoleColor::gray($e->getTraceAsString()), 4); - self::logError('Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues'); + self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4); + self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues'); } - private static function logError($message, int $indent_space = 0): void + private static function logError($message, int $indent_space = 0, bool $output_log = true): void { $spc_log = fopen(SPC_OUTPUT_LOG, 'a'); $msg = explode("\n", (string) $message); foreach ($msg as $v) { $line = str_pad($v, strlen($v) + $indent_space, ' ', STR_PAD_LEFT); fwrite($spc_log, strip_ansi_colors($line) . PHP_EOL); - echo ConsoleColor::red($line) . PHP_EOL; + if ($output_log) { + echo ConsoleColor::red($line) . PHP_EOL; + } + } + } + + /** + * Print array info to console and log. + */ + private static function printArrayInfo(array $info): void + { + $log_output = defined('DEBUG_MODE'); + $maxlen = 0; + foreach ($info as $k => $v) { + $maxlen = max(strlen($k), $maxlen); + } + foreach ($info as $k => $v) { + if (is_string($v)) { + if ($v === '') { + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow('""'), 4, $log_output); + } else { + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow($v), 4, $log_output); + } + } elseif (is_array($v) && !is_assoc_array($v)) { + if ($v === []) { + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow('[]'), 4, $log_output); + continue; + } + $first = array_shift($v); + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow($first), 4, $log_output); + foreach ($v as $vs) { + self::logError(str_pad('', $maxlen + 2) . ConsoleColor::yellow($vs), 4, $log_output); + } + } elseif (is_bool($v) || is_null($v)) { + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::cyan($v === true ? 'true' : ($v === false ? 'false' : 'null')), 4, $log_output); + } else { + self::logError($k . ': ' . str_pad('', $maxlen - strlen($k)) . ConsoleColor::yellow(json_encode($v, JSON_PRETTY_PRINT)), 4, $log_output); + } } } } diff --git a/src/SPC/exception/SPCException.php b/src/SPC/exception/SPCException.php index 95fee7d7..8a101cd1 100644 --- a/src/SPC/exception/SPCException.php +++ b/src/SPC/exception/SPCException.php @@ -24,8 +24,6 @@ use SPC\builder\windows\WindowsBuilder; */ abstract class SPCException extends \Exception { - private static ?array $build_php_extra_info = null; - private ?array $library_info = null; private ?array $extension_info = null; @@ -40,11 +38,6 @@ abstract class SPCException extends \Exception $this->loadStackTraceInfo(); } - public static function bindBuildPHPExtraInfo(array $indent_texts): void - { - self::$build_php_extra_info = $indent_texts; - } - public function bindExtensionInfo(array $extension_info): void { $this->extension_info = $extension_info; @@ -55,11 +48,6 @@ abstract class SPCException extends \Exception $this->extra_log_files[$key] = $filename; } - public function getBuildPHPExtraInfo(): ?array - { - return self::$build_php_extra_info; - } - /** * Returns an array containing information about the SPC module. * @@ -83,6 +71,8 @@ abstract class SPCException extends \Exception * * @return null|array{ * builder_class: string, + * builder_options: array, + * builder_function: string, * os: string, * file: null|string, * line: null|int, @@ -124,7 +114,7 @@ abstract class SPCException extends \Exception } // Check if the class is a subclass of LibraryBase - if (!$this->library_info && is_subclass_of($frame['class'], LibraryBase::class)) { + if (!$this->library_info && is_a($frame['class'], LibraryBase::class, true)) { try { $reflection = new \ReflectionClass($frame['class']); if ($reflection->hasConstant('NAME')) { @@ -152,21 +142,20 @@ abstract class SPCException extends \Exception } // Check if the class is a subclass of BuilderBase and the method is buildPHP - if (!$this->build_php_info && is_subclass_of($frame['class'], BuilderBase::class) && $frame['function'] === 'buildPHP') { - $reflection = new \ReflectionClass($frame['class']); - if ($reflection->hasProperty('options')) { - $options = $reflection->getProperty('options')->getValue(); - } + if (!$this->build_php_info && is_a($frame['class'], BuilderBase::class, true)) { + $options = ExceptionHandler::$bind_builder?->getOptions() ?? []; + $os = match (get_class(ExceptionHandler::$bind_builder ?? $frame['class'])) { + BSDBuilder::class => 'BSD', + LinuxBuilder::class => 'Linux', + MacOSBuilder::class => 'macOS', + WindowsBuilder::class => 'Windows', + default => 'Unknown', + }; $this->build_php_info = [ 'builder_class' => $frame['class'], - 'builder_options' => $options ?? [], - 'os' => match (true) { - is_a($frame['class'], BSDBuilder::class, true) => 'BSD', - is_a($frame['class'], LinuxBuilder::class, true) => 'Linux', - is_a($frame['class'], MacOSBuilder::class, true) => 'macOS', - is_a($frame['class'], WindowsBuilder::class, true) => 'Windows', - default => 'Unknown', - }, + 'builder_options' => $options, + 'builder_function' => $frame['function'], + 'os' => $os, 'file' => $frame['file'] ?? null, 'line' => $frame['line'] ?? null, ]; From b34b6594debdbb18d8147f82a023979c999acb4a Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 11 Aug 2025 12:05:41 +0800 Subject: [PATCH 02/14] Suggestions --- src/SPC/builder/BuilderProvider.php | 2 +- src/SPC/command/BuildPHPCommand.php | 2 +- src/SPC/exception/ExceptionHandler.php | 41 ++++++++++++++++++++------ src/SPC/exception/SPCException.php | 18 ----------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index 6fbec300..3c52903a 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -32,7 +32,7 @@ class BuilderProvider }; // bind the builder to ExceptionHandler - ExceptionHandler::$bind_builder = self::$builder; + ExceptionHandler::setBindBuilder(self::$builder); return self::$builder; } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 5f57653d..f4f1f478 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -167,7 +167,7 @@ class BuildPHPCommand extends BuildCommand $this->printFormatInfo($indent_texts); // bind extra info to exception handler - ExceptionHandler::$bind_build_php_extra_info = $indent_texts; + ExceptionHandler::setBindBuildPhpExtraInfo($indent_texts); logger()->notice('Build will start after 2s ...'); sleep(2); diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index d41b3f08..3966f71e 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -5,6 +5,10 @@ declare(strict_types=1); namespace SPC\exception; use SPC\builder\BuilderBase; +use SPC\builder\freebsd\BSDBuilder; +use SPC\builder\linux\LinuxBuilder; +use SPC\builder\macos\MacOSBuilder; +use SPC\builder\windows\WindowsBuilder; use ZM\Logger\ConsoleColor; class ExceptionHandler @@ -28,10 +32,10 @@ class ExceptionHandler ]; /** @var null|BuilderBase Builder binding */ - public static ?BuilderBase $bind_builder = null; + private static ?BuilderBase $bind_builder = null; /** @var array Build PHP extra info binding */ - public static array $bind_build_php_extra_info = []; + private static array $bind_build_php_extra_info = []; public static function handleSPCException(SPCException $e): void { @@ -47,7 +51,7 @@ class ExceptionHandler SPCInternalException::class => "✗ SPC internal error: {$e->getMessage()}", ValidationException::class => "⚠ Validation failed: {$e->getMessage()}", WrongUsageException::class => $e->getMessage(), - default => "✗Unknown SPC exception {$class}: {$e->getMessage()}", + default => "✗ Unknown SPC exception {$class}: {$e->getMessage()}", }; self::logError($head_msg); @@ -61,12 +65,19 @@ class ExceptionHandler self::logError("----------------------------------------\n"); // get the SPCException module - if ($php_info = $e->getBuildPHPInfo()) { - self::logError('Failed module: ' . ConsoleColor::yellow("Builder for {$php_info['os']}")); - } elseif ($lib_info = $e->getLibraryInfo()) { + if ($lib_info = $e->getLibraryInfo()) { self::logError('Failed module: ' . ConsoleColor::yellow("library {$lib_info['library_name']} builder for {$lib_info['os']}")); } elseif ($ext_info = $e->getExtensionInfo()) { self::logError('Failed module: ' . ConsoleColor::yellow("shared extension {$ext_info['extension_name']} builder")); + } elseif (self::$bind_builder) { + $os = match (get_class(self::$bind_builder)) { + WindowsBuilder::class => 'Windows', + MacOSBuilder::class => 'macOS', + LinuxBuilder::class => 'Linux', + BSDBuilder::class => 'FreeBSD', + default => 'Unknown OS', + }; + self::logError('Failed module: ' . ConsoleColor::yellow("Builder for {$os}")); } elseif (!in_array($class, self::KNOWN_EXCEPTIONS)) { self::logError('Failed From: ' . ConsoleColor::yellow('Unknown SPC module ' . $class)); } @@ -118,12 +129,14 @@ class ExceptionHandler } // get the full builder options if possible - if (self::$bind_builder && $e->getBuildPHPInfo()) { + if ($e->getBuildPHPInfo()) { $info = $e->getBuildPHPInfo(); self::logError('', output_log: defined('DEBUG_MODE')); self::logError('Builder function: ' . ConsoleColor::yellow($info['builder_function']), output_log: defined('DEBUG_MODE')); - self::logError('Builder options:', output_log: defined('DEBUG_MODE')); - self::printArrayInfo(self::$bind_builder->getOptions()); + if (self::$bind_builder) { + self::logError('Builder options:', output_log: defined('DEBUG_MODE')); + self::printArrayInfo(self::$bind_builder->getOptions()); + } } self::logError("\n----------------------------------------\n"); @@ -151,6 +164,16 @@ class ExceptionHandler self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues'); } + public static function setBindBuilder(?BuilderBase $bind_builder): void + { + self::$bind_builder = $bind_builder; + } + + public static function setBindBuildPhpExtraInfo(array $bind_build_php_extra_info): void + { + self::$bind_build_php_extra_info = $bind_build_php_extra_info; + } + private static function logError($message, int $indent_space = 0, bool $output_log = true): void { $spc_log = fopen(SPC_OUTPUT_LOG, 'a'); diff --git a/src/SPC/exception/SPCException.php b/src/SPC/exception/SPCException.php index 8a101cd1..e8b23361 100644 --- a/src/SPC/exception/SPCException.php +++ b/src/SPC/exception/SPCException.php @@ -5,15 +5,11 @@ declare(strict_types=1); namespace SPC\exception; use SPC\builder\BuilderBase; -use SPC\builder\freebsd\BSDBuilder; use SPC\builder\freebsd\library\BSDLibraryBase; use SPC\builder\LibraryBase; use SPC\builder\linux\library\LinuxLibraryBase; -use SPC\builder\linux\LinuxBuilder; use SPC\builder\macos\library\MacOSLibraryBase; -use SPC\builder\macos\MacOSBuilder; use SPC\builder\windows\library\WindowsLibraryBase; -use SPC\builder\windows\WindowsBuilder; /** * Base class for SPC exceptions. @@ -70,10 +66,7 @@ abstract class SPCException extends \Exception * Returns an array containing information about the PHP build process. * * @return null|array{ - * builder_class: string, - * builder_options: array, * builder_function: string, - * os: string, * file: null|string, * line: null|int, * } an array containing PHP build information @@ -143,19 +136,8 @@ abstract class SPCException extends \Exception // Check if the class is a subclass of BuilderBase and the method is buildPHP if (!$this->build_php_info && is_a($frame['class'], BuilderBase::class, true)) { - $options = ExceptionHandler::$bind_builder?->getOptions() ?? []; - $os = match (get_class(ExceptionHandler::$bind_builder ?? $frame['class'])) { - BSDBuilder::class => 'BSD', - LinuxBuilder::class => 'Linux', - MacOSBuilder::class => 'macOS', - WindowsBuilder::class => 'Windows', - default => 'Unknown', - }; $this->build_php_info = [ - 'builder_class' => $frame['class'], - 'builder_options' => $options, 'builder_function' => $frame['function'], - 'os' => $os, 'file' => $frame['file'] ?? null, 'line' => $frame['line'] ?? null, ]; From d3840b19fa812459e5987697d9b2a68d611741fe Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:29:36 +0800 Subject: [PATCH 03/14] Update src/SPC/builder/BuilderProvider.php Co-authored-by: Marc --- src/SPC/builder/BuilderProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index 3c52903a..ec6141e6 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -32,7 +32,7 @@ class BuilderProvider }; // bind the builder to ExceptionHandler - ExceptionHandler::setBindBuilder(self::$builder); + ExceptionHandler::bindBuilder(self::$builder); return self::$builder; } From a73c097c94d8bd0539c98875da08b215d78307bd Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:29:42 +0800 Subject: [PATCH 04/14] Update src/SPC/command/BuildPHPCommand.php Co-authored-by: Marc --- src/SPC/command/BuildPHPCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index f4f1f478..aaf902ba 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -167,7 +167,7 @@ class BuildPHPCommand extends BuildCommand $this->printFormatInfo($indent_texts); // bind extra info to exception handler - ExceptionHandler::setBindBuildPhpExtraInfo($indent_texts); + ExceptionHandler::bindBuildPhpExtraInfo($indent_texts); logger()->notice('Build will start after 2s ...'); sleep(2); From 5ba0de12eb7d96ba1c293cbb7c67e67eef75a694 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:29:48 +0800 Subject: [PATCH 05/14] Update src/SPC/exception/ExceptionHandler.php Co-authored-by: Marc --- src/SPC/exception/ExceptionHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 3966f71e..f98fc341 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -164,7 +164,7 @@ class ExceptionHandler self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues'); } - public static function setBindBuilder(?BuilderBase $bind_builder): void + public static function bindBuilder(?BuilderBase $bind_builder): void { self::$bind_builder = $bind_builder; } From d3a5be13ea6be294625445596f248bb56bec276f Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:29:54 +0800 Subject: [PATCH 06/14] Update src/SPC/exception/ExceptionHandler.php Co-authored-by: Marc --- src/SPC/exception/ExceptionHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index f98fc341..19efbadd 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -169,7 +169,7 @@ class ExceptionHandler self::$bind_builder = $bind_builder; } - public static function setBindBuildPhpExtraInfo(array $bind_build_php_extra_info): void + public static function bindBuildPhpExtraInfo(array $build_php_extra_info): void { self::$bind_build_php_extra_info = $bind_build_php_extra_info; } From 9978a56b1e9a7da169509f07bf546244fb187f42 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:29:59 +0800 Subject: [PATCH 07/14] Update src/SPC/exception/ExceptionHandler.php Co-authored-by: Marc --- src/SPC/exception/ExceptionHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 19efbadd..1a35b59f 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -171,7 +171,7 @@ class ExceptionHandler public static function bindBuildPhpExtraInfo(array $build_php_extra_info): void { - self::$bind_build_php_extra_info = $bind_build_php_extra_info; + self::$build_php_extra_info = $build_php_extra_info; } private static function logError($message, int $indent_space = 0, bool $output_log = true): void From e96b4f55416a6d80fbbc5214af44cb5138f9ad74 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:30:04 +0800 Subject: [PATCH 08/14] Update src/SPC/exception/ExceptionHandler.php Co-authored-by: Marc --- src/SPC/exception/ExceptionHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 1a35b59f..b81712d0 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -32,7 +32,7 @@ class ExceptionHandler ]; /** @var null|BuilderBase Builder binding */ - private static ?BuilderBase $bind_builder = null; + private static ?BuilderBase $builder = null; /** @var array Build PHP extra info binding */ private static array $bind_build_php_extra_info = []; From 4fd8afcee4f6e1aa391c2578f35b6f141651d343 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 11 Aug 2025 13:30:10 +0800 Subject: [PATCH 09/14] Update src/SPC/exception/ExceptionHandler.php Co-authored-by: Marc --- src/SPC/exception/ExceptionHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index b81712d0..3856509e 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -35,7 +35,7 @@ class ExceptionHandler private static ?BuilderBase $builder = null; /** @var array Build PHP extra info binding */ - private static array $bind_build_php_extra_info = []; + private static array $build_php_extra_info = []; public static function handleSPCException(SPCException $e): void { From 2e616af836c61ce5e0c5b2b40fc712885eddbc48 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 11 Aug 2025 13:32:59 +0800 Subject: [PATCH 10/14] PHPStan fix --- src/SPC/exception/ExceptionHandler.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 3856509e..d316d643 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -69,8 +69,8 @@ class ExceptionHandler self::logError('Failed module: ' . ConsoleColor::yellow("library {$lib_info['library_name']} builder for {$lib_info['os']}")); } elseif ($ext_info = $e->getExtensionInfo()) { self::logError('Failed module: ' . ConsoleColor::yellow("shared extension {$ext_info['extension_name']} builder")); - } elseif (self::$bind_builder) { - $os = match (get_class(self::$bind_builder)) { + } elseif (self::$builder) { + $os = match (get_class(self::$builder)) { WindowsBuilder::class => 'Windows', MacOSBuilder::class => 'macOS', LinuxBuilder::class => 'Linux', @@ -122,7 +122,7 @@ class ExceptionHandler } // get the full build info if possible - if ($info = ExceptionHandler::$bind_build_php_extra_info) { + if ($info = ExceptionHandler::$build_php_extra_info) { self::logError('', output_log: defined('DEBUG_MODE')); self::logError('Build PHP extra info:', output_log: defined('DEBUG_MODE')); self::printArrayInfo($info); @@ -133,9 +133,9 @@ class ExceptionHandler $info = $e->getBuildPHPInfo(); self::logError('', output_log: defined('DEBUG_MODE')); self::logError('Builder function: ' . ConsoleColor::yellow($info['builder_function']), output_log: defined('DEBUG_MODE')); - if (self::$bind_builder) { + if (self::$builder) { self::logError('Builder options:', output_log: defined('DEBUG_MODE')); - self::printArrayInfo(self::$bind_builder->getOptions()); + self::printArrayInfo(self::$builder->getOptions()); } } @@ -166,7 +166,7 @@ class ExceptionHandler public static function bindBuilder(?BuilderBase $bind_builder): void { - self::$bind_builder = $bind_builder; + self::$builder = $bind_builder; } public static function bindBuildPhpExtraInfo(array $build_php_extra_info): void From a3ae1eb2f0402588f2489394019803f8ba1e52ee Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 15 Aug 2025 11:54:34 +0800 Subject: [PATCH 11/14] Remove redundant builer options --- src/SPC/exception/ExceptionHandler.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index d316d643..44b82b06 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -133,10 +133,6 @@ class ExceptionHandler $info = $e->getBuildPHPInfo(); self::logError('', output_log: defined('DEBUG_MODE')); self::logError('Builder function: ' . ConsoleColor::yellow($info['builder_function']), output_log: defined('DEBUG_MODE')); - if (self::$builder) { - self::logError('Builder options:', output_log: defined('DEBUG_MODE')); - self::printArrayInfo(self::$builder->getOptions()); - } } self::logError("\n----------------------------------------\n"); From d0412a88df3ac630339050b5faba3de17c0cfb38 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 15 Aug 2025 12:04:06 +0800 Subject: [PATCH 12/14] Use PatchException instead of ExecutionException for patchFile --- src/SPC/store/SourcePatcher.php | 74 ++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index b92b945c..388ee1e6 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -8,6 +8,7 @@ use SPC\builder\BuilderBase; use SPC\builder\linux\SystemUtil; use SPC\builder\unix\UnixBuilderBase; use SPC\builder\windows\WindowsBuilder; +use SPC\exception\ExecutionException; use SPC\exception\FileSystemException; use SPC\exception\PatchException; use SPC\util\SPCTarget; @@ -190,46 +191,51 @@ class SourcePatcher */ public static function patchFile(string $patch_name, string $cwd, bool $reverse = false): bool { - if (FileSystem::isRelativePath($patch_name)) { - $patch_file = ROOT_DIR . "/src/globals/patch/{$patch_name}"; - } else { - $patch_file = $patch_name; - } - if (!file_exists($patch_file)) { - return false; - } + try { + if (FileSystem::isRelativePath($patch_name)) { + $patch_file = ROOT_DIR . "/src/globals/patch/{$patch_name}"; + } else { + $patch_file = $patch_name; + } + if (!file_exists($patch_file)) { + return false; + } - $patch_str = FileSystem::convertPath($patch_file); - if (!file_exists($patch_str)) { - throw new PatchException($patch_name, "Patch file [{$patch_str}] does not exist"); - } + $patch_str = FileSystem::convertPath($patch_file); + if (!file_exists($patch_str)) { + throw new PatchException($patch_name, "Patch file [{$patch_str}] does not exist"); + } - // Copy patch from phar - if (str_starts_with($patch_str, 'phar://')) { - $filename = pathinfo($patch_file, PATHINFO_BASENAME); - file_put_contents(SOURCE_PATH . "/{$filename}", file_get_contents($patch_file)); - $patch_str = FileSystem::convertPath(SOURCE_PATH . "/{$filename}"); - } + // Copy patch from phar + if (str_starts_with($patch_str, 'phar://')) { + $filename = pathinfo($patch_file, PATHINFO_BASENAME); + file_put_contents(SOURCE_PATH . "/{$filename}", file_get_contents($patch_file)); + $patch_str = FileSystem::convertPath(SOURCE_PATH . "/{$filename}"); + } - // detect - $detect_reverse = !$reverse; - $detect_cmd = 'cd ' . escapeshellarg($cwd) . ' && ' - . (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . escapeshellarg($patch_str) - . ' | patch --dry-run -p1 -s -f ' . ($detect_reverse ? '-R' : '') - . ' > ' . (PHP_OS_FAMILY === 'Windows' ? 'NUL' : '/dev/null') . ' 2>&1'; - exec($detect_cmd, $output, $detect_status); + // detect + $detect_reverse = !$reverse; + $detect_cmd = 'cd ' . escapeshellarg($cwd) . ' && ' + . (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . escapeshellarg($patch_str) + . ' | patch --dry-run -p1 -s -f ' . ($detect_reverse ? '-R' : '') + . ' > ' . (PHP_OS_FAMILY === 'Windows' ? 'NUL' : '/dev/null') . ' 2>&1'; + exec($detect_cmd, $output, $detect_status); - if ($detect_status === 0) { + if ($detect_status === 0) { + return true; + } + + // apply patch + $apply_cmd = 'cd ' . escapeshellarg($cwd) . ' && ' + . (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . escapeshellarg($patch_str) + . ' | patch -p1 ' . ($reverse ? '-R' : ''); + + f_passthru($apply_cmd); return true; + } catch (ExecutionException $e) { + // If patch failed, throw exception + throw new PatchException($patch_name, "Patch file [{$patch_name}] failed to apply", previous: $e); } - - // apply patch - $apply_cmd = 'cd ' . escapeshellarg($cwd) . ' && ' - . (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . escapeshellarg($patch_str) - . ' | patch -p1 ' . ($reverse ? '-R' : ''); - - f_passthru($apply_cmd); - return true; } public static function patchOpenssl11Darwin(): bool From ad25ac49b8034052be949dacf45972d16a1f7e93 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 15 Aug 2025 12:28:26 +0800 Subject: [PATCH 13/14] Update to beta1, extension test --- src/SPC/store/source/PhpSource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/store/source/PhpSource.php b/src/SPC/store/source/PhpSource.php index 242d186a..c33e172f 100644 --- a/src/SPC/store/source/PhpSource.php +++ b/src/SPC/store/source/PhpSource.php @@ -16,7 +16,7 @@ class PhpSource extends CustomSourceBase { $major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.4'; if ($major === '8.5') { - Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://downloads.php.net/~daniels/php-8.5.0alpha4.tar.xz'], $force); + Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://downloads.php.net/~edorian/php-8.5.0beta1.tar.xz'], $force); } elseif ($major === 'git') { Downloader::downloadSource('php-src', ['type' => 'git', 'url' => 'https://github.com/php/php-src.git', 'rev' => 'master'], $force); } else { From 2cabaf6402749c0373dcc1cc19be96170e2008a8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 15 Aug 2025 13:19:14 +0800 Subject: [PATCH 14/14] 8.5 extension test --- .github/workflows/ext-matrix-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ext-matrix-tests.yml b/.github/workflows/ext-matrix-tests.yml index 2396718c..22db8ad6 100644 --- a/.github/workflows/ext-matrix-tests.yml +++ b/.github/workflows/ext-matrix-tests.yml @@ -82,7 +82,7 @@ jobs: - zlib - zstd php-version: - - "git" + - "8.5" operating-system: - "ubuntu-latest" #- "macos-13"