mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
Refactor exception handler to v3, use standard shell exitcode
This commit is contained in:
parent
ee5aabbe34
commit
bbab685247
6
bin/spc
6
bin/spc
@ -21,10 +21,8 @@ if (PHP_VERSION_ID < 80400) {
|
|||||||
try {
|
try {
|
||||||
(new ConsoleApplication())->run();
|
(new ConsoleApplication())->run();
|
||||||
} catch (SPCException $e) {
|
} catch (SPCException $e) {
|
||||||
ExceptionHandler::handleSPCException($e);
|
exit(ExceptionHandler::handleSPCException($e));
|
||||||
exit(1);
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ExceptionHandler::handleDefaultException($e);
|
exit(ExceptionHandler::handleDefaultException($e));
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,8 @@ use ZM\Logger\ConsoleColor;
|
|||||||
|
|
||||||
abstract class BaseCommand extends Command
|
abstract class BaseCommand extends Command
|
||||||
{
|
{
|
||||||
|
use ReturnCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message of the day (MOTD) displayed when the command is run.
|
* The message of the day (MOTD) displayed when the command is run.
|
||||||
* You can customize this to show your application's name and version if you are using SPC in vendor mode.
|
* You can customize this to show your application's name and version if you are using SPC in vendor mode.
|
||||||
@ -101,12 +103,10 @@ abstract class BaseCommand extends Command
|
|||||||
return $this->handle();
|
return $this->handle();
|
||||||
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (SPCException $e) {
|
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (SPCException $e) {
|
||||||
// Handle SPCException and log it
|
// Handle SPCException and log it
|
||||||
ExceptionHandler::handleSPCException($e);
|
return ExceptionHandler::handleSPCException($e);
|
||||||
return static::FAILURE;
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Handle any other exceptions
|
// Handle any other exceptions
|
||||||
ExceptionHandler::handleDefaultException($e);
|
return ExceptionHandler::handleDefaultException($e);
|
||||||
return static::FAILURE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,8 @@ abstract class BaseCommand extends Command
|
|||||||
|
|
||||||
// Don't show commit ID when running in phar
|
// Don't show commit ID when running in phar
|
||||||
if (\Phar::running()) {
|
if (\Phar::running()) {
|
||||||
return $version;
|
$stable = file_exists(ROOT_DIR . '/src/.release') ? 'stable' : 'unstable';
|
||||||
|
return "{$version} ({$stable})";
|
||||||
}
|
}
|
||||||
|
|
||||||
$commitId = $this->getGitCommitShortId();
|
$commitId = $this->getGitCommitShortId();
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class EnvCommand extends BaseCommand
|
|||||||
$env = $this->getArgument('env');
|
$env = $this->getArgument('env');
|
||||||
if (($val = getenv($env)) === false) {
|
if (($val = getenv($env)) === false) {
|
||||||
$this->output->writeln("<error>Environment variable '{$env}' is not set.</error>");
|
$this->output->writeln("<error>Environment variable '{$env}' is not set.</error>");
|
||||||
return static::FAILURE;
|
return static::USER_ERROR;
|
||||||
}
|
}
|
||||||
if (is_array($val)) {
|
if (is_array($val)) {
|
||||||
foreach ($val as $k => $v) {
|
foreach ($val as $k => $v) {
|
||||||
|
|||||||
@ -29,6 +29,6 @@ class IsInstalledCommand extends BaseCommand
|
|||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
$this->output->writeln("<error>Package [{$package}] is not installed.</error>");
|
$this->output->writeln("<error>Package [{$package}] is not installed.</error>");
|
||||||
return static::FAILURE;
|
return static::USER_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class LintConfigCommand extends BaseCommand
|
|||||||
|
|
||||||
if ($checkOnly && $hasChanges) {
|
if ($checkOnly && $hasChanges) {
|
||||||
$this->output->writeln('<error>Some config files need sorting. Run "bin/spc dev:lint-config" to fix them.</error>');
|
$this->output->writeln('<error>Some config files need sorting. Run "bin/spc dev:lint-config" to fix them.</error>');
|
||||||
return static::FAILURE;
|
return static::VALIDATION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
@ -125,7 +125,7 @@ class LintConfigCommand extends BaseCommand
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ksort($data);
|
ksort($data);
|
||||||
foreach ($data as $artifact_name => &$config) {
|
foreach ($data as &$config) {
|
||||||
uksort($config, $config_type === 'artifact' ? [$this, 'artifactSortKey'] : [$this, 'packageSortKey']);
|
uksort($config, $config_type === 'artifact' ? [$this, 'artifactSortKey'] : [$this, 'packageSortKey']);
|
||||||
}
|
}
|
||||||
unset($config);
|
unset($config);
|
||||||
|
|||||||
@ -28,6 +28,6 @@ class ShellCommand extends BaseCommand
|
|||||||
return $code;
|
return $code;
|
||||||
}
|
}
|
||||||
$this->output->writeln('<error>Unsupported OS for shell command.</error>');
|
$this->output->writeln('<error>Unsupported OS for shell command.</error>');
|
||||||
return static::FAILURE;
|
return static::ENVIRONMENT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,6 @@ class DoctorCommand extends BaseCommand
|
|||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::FAILURE;
|
return static::ENVIRONMENT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,7 +71,7 @@ class DumpLicenseCommand extends BaseCommand
|
|||||||
$this->output->writeln(' - --for-extensions: <info>dump-license --for-extensions=openssl,mbstring</info>');
|
$this->output->writeln(' - --for-extensions: <info>dump-license --for-extensions=openssl,mbstring</info>');
|
||||||
$this->output->writeln(' - --for-libs: <info>dump-license --for-libs=openssl,zlib</info>');
|
$this->output->writeln(' - --for-libs: <info>dump-license --for-libs=openssl,zlib</info>');
|
||||||
$this->output->writeln(' - --for-packages: <info>dump-license --for-packages=php,libssl</info>');
|
$this->output->writeln(' - --for-packages: <info>dump-license --for-packages=php,libssl</info>');
|
||||||
return self::FAILURE;
|
return static::USER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deduplicate artifacts
|
// Deduplicate artifacts
|
||||||
@ -90,11 +90,11 @@ class DumpLicenseCommand extends BaseCommand
|
|||||||
InteractiveTerm::success('Licenses dumped successfully: ' . $dump_dir);
|
InteractiveTerm::success('Licenses dumped successfully: ' . $dump_dir);
|
||||||
// $this->output->writeln("<info>✓ Successfully dumped licenses to: {$dump_dir}</info>");
|
// $this->output->writeln("<info>✓ Successfully dumped licenses to: {$dump_dir}</info>");
|
||||||
// $this->output->writeln("<comment> Total artifacts: " . count($artifacts_to_dump) . '</comment>');
|
// $this->output->writeln("<comment> Total artifacts: " . count($artifacts_to_dump) . '</comment>');
|
||||||
return self::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->output->writeln('<error>Failed to dump licenses</error>');
|
$this->output->writeln('<error>Failed to dump licenses</error>');
|
||||||
return self::FAILURE;
|
return static::INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class ExtractCommand extends BaseCommand
|
|||||||
$artifact = ArtifactLoader::getArtifactInstance($name);
|
$artifact = ArtifactLoader::getArtifactInstance($name);
|
||||||
if ($artifact === null) {
|
if ($artifact === null) {
|
||||||
$this->output->writeln("<error>Artifact '{$name}' not found.</error>");
|
$this->output->writeln("<error>Artifact '{$name}' not found.</error>");
|
||||||
return static::FAILURE;
|
return static::USER_ERROR;
|
||||||
}
|
}
|
||||||
$artifacts[$name] = $artifact;
|
$artifacts[$name] = $artifact;
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/StaticPHP/Command/ReturnCode.php
Normal file
42
src/StaticPHP/Command/ReturnCode.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection PhpMissingClassConstantTypeInspection */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StaticPHP\Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return codes for command execution.
|
||||||
|
*
|
||||||
|
* This enum defines standard return codes that can be used by commands to indicate
|
||||||
|
* the result of their execution. It includes codes for success, various types of errors,
|
||||||
|
* and an interrupt signal.
|
||||||
|
*/
|
||||||
|
trait ReturnCode
|
||||||
|
{
|
||||||
|
public const int OK = 0;
|
||||||
|
|
||||||
|
public const SUCCESS = 0; // alias of OK
|
||||||
|
|
||||||
|
public const int INTERNAL_ERROR = 1; // unsorted or internal error
|
||||||
|
|
||||||
|
/** @deprecated Use specified error code instead */
|
||||||
|
public const FAILURE = 1;
|
||||||
|
|
||||||
|
public const int USER_ERROR = 2; // wrong usage or user error
|
||||||
|
|
||||||
|
public const int ENVIRONMENT_ERROR = 3; // environment not suitable for operation
|
||||||
|
|
||||||
|
public const int VALIDATION_ERROR = 4; // validation failed
|
||||||
|
|
||||||
|
public const int FILE_SYSTEM_ERROR = 5; // file system related error
|
||||||
|
|
||||||
|
public const int DOWNLOAD_ERROR = 6; // network related error
|
||||||
|
|
||||||
|
public const int BUILD_ERROR = 7; // build process error
|
||||||
|
|
||||||
|
public const int PATCH_ERROR = 8; // patching process error
|
||||||
|
|
||||||
|
public const int INTERRUPT_SIGNAL = 130; // process interrupted by user (e.g., Ctrl+C)
|
||||||
|
}
|
||||||
@ -53,6 +53,6 @@ class SPCConfigCommand extends BaseCommand
|
|||||||
default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}",
|
default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}",
|
||||||
});
|
});
|
||||||
|
|
||||||
return 0;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,15 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace StaticPHP\Exception;
|
namespace StaticPHP\Exception;
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
use StaticPHP\Command\BaseCommand;
|
||||||
use SPC\builder\freebsd\BSDBuilder;
|
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
|
||||||
use SPC\builder\windows\WindowsBuilder;
|
|
||||||
use StaticPHP\DI\ApplicationContext;
|
use StaticPHP\DI\ApplicationContext;
|
||||||
use StaticPHP\Util\InteractiveTerm;
|
use StaticPHP\Util\InteractiveTerm;
|
||||||
use ZM\Logger\ConsoleColor;
|
use ZM\Logger\ConsoleColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception handler for StaticPHP.
|
||||||
|
* Provides centralized exception handling for the Package-based architecture.
|
||||||
|
*/
|
||||||
class ExceptionHandler
|
class ExceptionHandler
|
||||||
{
|
{
|
||||||
public const array KNOWN_EXCEPTIONS = [
|
public const array KNOWN_EXCEPTIONS = [
|
||||||
@ -35,28 +35,25 @@ class ExceptionHandler
|
|||||||
RegistryException::class,
|
RegistryException::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var null|BuilderBase Builder binding */
|
|
||||||
private static ?BuilderBase $builder = null;
|
|
||||||
|
|
||||||
/** @var array<string, mixed> Build PHP extra info binding */
|
/** @var array<string, mixed> Build PHP extra info binding */
|
||||||
private static array $build_php_extra_info = [];
|
private static array $build_php_extra_info = [];
|
||||||
|
|
||||||
public static function handleSPCException(SPCException $e): void
|
public static function handleSPCException(SPCException $e): int
|
||||||
{
|
{
|
||||||
// XXX error: yyy
|
// XXX error: yyy
|
||||||
$head_msg = match ($class = get_class($e)) {
|
$head_msg = match ($class = get_class($e)) {
|
||||||
BuildFailureException::class => "✗ Build failed: {$e->getMessage()}",
|
BuildFailureException::class => "✘ Build failed: {$e->getMessage()}",
|
||||||
DownloaderException::class => "✗ Download failed: {$e->getMessage()}",
|
DownloaderException::class => "✘ Download failed: {$e->getMessage()}",
|
||||||
EnvironmentException::class => "⚠ Environment check failed: {$e->getMessage()}",
|
EnvironmentException::class => "⚠ Environment check failed: {$e->getMessage()}",
|
||||||
ExecutionException::class => "✗ Command execution failed: {$e->getMessage()}",
|
ExecutionException::class => "✘ Command execution failed: {$e->getMessage()}",
|
||||||
FileSystemException::class => "✗ File system error: {$e->getMessage()}",
|
FileSystemException::class => "✘ File system error: {$e->getMessage()}",
|
||||||
InterruptException::class => "⚠ Build interrupted by user: {$e->getMessage()}",
|
InterruptException::class => "⚠ Build interrupted by user: {$e->getMessage()}",
|
||||||
PatchException::class => "✗ Patch apply failed: {$e->getMessage()}",
|
PatchException::class => "✘ Patch apply failed: {$e->getMessage()}",
|
||||||
SPCInternalException::class => "✗ SPC internal error: {$e->getMessage()}",
|
SPCInternalException::class => "✘ SPC internal error: {$e->getMessage()}",
|
||||||
ValidationException::class => "⚠ Validation failed: {$e->getMessage()}",
|
ValidationException::class => "⚠ Validation failed: {$e->getMessage()}",
|
||||||
WrongUsageException::class => $e->getMessage(),
|
WrongUsageException::class => $e->getMessage(),
|
||||||
RegistryException::class => "✗ Registry parsing error: {$e->getMessage()}",
|
RegistryException::class => "✘ Registry error: {$e->getMessage()}",
|
||||||
default => "✗ Unknown SPC exception {$class}: {$e->getMessage()}",
|
default => "✘ Unknown SPC exception {$class}: {$e->getMessage()}",
|
||||||
};
|
};
|
||||||
self::logError($head_msg);
|
self::logError($head_msg);
|
||||||
|
|
||||||
@ -64,83 +61,10 @@ class ExceptionHandler
|
|||||||
$minor_logs = in_array($class, self::MINOR_LOG_EXCEPTIONS, true);
|
$minor_logs = in_array($class, self::MINOR_LOG_EXCEPTIONS, true);
|
||||||
|
|
||||||
if ($minor_logs) {
|
if ($minor_logs) {
|
||||||
return;
|
return self::getReturnCode($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
self::logError("----------------------------------------\n");
|
self::printModuleErrorInfo($e);
|
||||||
|
|
||||||
// get the SPCException module
|
|
||||||
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::$builder) {
|
|
||||||
$os = match (get_class(self::$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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get command execution info
|
|
||||||
if ($e instanceof ExecutionException) {
|
|
||||||
self::logError('');
|
|
||||||
self::logError('Failed command: ' . ConsoleColor::yellow($e->getExecutionCommand()));
|
|
||||||
if ($cd = $e->getCd()) {
|
|
||||||
self::logError('Command executed in: ' . ConsoleColor::yellow($cd));
|
|
||||||
}
|
|
||||||
if ($env = $e->getEnv()) {
|
|
||||||
self::logError('Command inline env variables:');
|
|
||||||
foreach ($env as $k => $v) {
|
|
||||||
self::logError(ConsoleColor::yellow("{$k}={$v}"), 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// validation error
|
|
||||||
if ($e instanceof ValidationException) {
|
|
||||||
self::logError('Failed validation module: ' . ConsoleColor::yellow($e->getValidationModuleString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// environment error
|
|
||||||
if ($e instanceof EnvironmentException) {
|
|
||||||
self::logError('Failed environment check: ' . ConsoleColor::yellow($e->getMessage()));
|
|
||||||
if (($solution = $e->getSolution()) !== null) {
|
|
||||||
self::logError('Solution: ' . ConsoleColor::yellow($solution));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get patch info
|
|
||||||
if ($e instanceof PatchException) {
|
|
||||||
self::logError("Failed patch module: {$e->getPatchModule()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// get internal trace
|
|
||||||
if ($e instanceof SPCInternalException) {
|
|
||||||
self::logError('Internal trace:');
|
|
||||||
self::logError(ConsoleColor::gray("{$e->getTraceAsString()}\n"), 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the full build info if possible
|
|
||||||
if ($info = ExceptionHandler::$build_php_extra_info) {
|
|
||||||
self::logError('', output_log: ApplicationContext::isDebug());
|
|
||||||
self::logError('Build PHP extra info:', output_log: ApplicationContext::isDebug());
|
|
||||||
self::printArrayInfo($info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the full builder options if possible
|
|
||||||
if ($e->getBuildPHPInfo()) {
|
|
||||||
$info = $e->getBuildPHPInfo();
|
|
||||||
self::logError('', output_log: ApplicationContext::isDebug());
|
|
||||||
self::logError('Builder function: ' . ConsoleColor::yellow($info['builder_function']), output_log: ApplicationContext::isDebug());
|
|
||||||
}
|
|
||||||
|
|
||||||
self::logError("\n----------------------------------------\n");
|
|
||||||
|
|
||||||
// convert log file path if in docker
|
// convert log file path if in docker
|
||||||
$spc_log_convert = get_display_path(SPC_OUTPUT_LOG);
|
$spc_log_convert = get_display_path(SPC_OUTPUT_LOG);
|
||||||
@ -153,28 +77,25 @@ class ExceptionHandler
|
|||||||
}
|
}
|
||||||
if ($e->getExtraLogFiles() !== []) {
|
if ($e->getExtraLogFiles() !== []) {
|
||||||
foreach ($e->getExtraLogFiles() as $key => $file) {
|
foreach ($e->getExtraLogFiles() as $key => $file) {
|
||||||
self::logError("⚠ Log file [{$key}] is saved in: " . ConsoleColor::cyan("{$spc_logs_dir_convert}/{$file}"));
|
self::logError('⚠ Log file ' . ConsoleColor::cyan($key) . ' is saved in: ' . ConsoleColor::cyan("{$spc_logs_dir_convert}/{$file}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ApplicationContext::isDebug()) {
|
if (!ApplicationContext::isDebug()) {
|
||||||
self::logError('⚠ If you want to see more details in console, use `--debug` option.');
|
self::logError('⚠ If you want to see more details in console, use `-vvv` option.');
|
||||||
}
|
}
|
||||||
|
return self::getReturnCode($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function handleDefaultException(\Throwable $e): void
|
public static function handleDefaultException(\Throwable $e): int
|
||||||
{
|
{
|
||||||
$class = get_class($e);
|
$class = get_class($e);
|
||||||
$file = $e->getFile();
|
$file = $e->getFile();
|
||||||
$line = $e->getLine();
|
$line = $e->getLine();
|
||||||
self::logError("✗ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n");
|
self::logError("✘ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n");
|
||||||
self::logError('Stack trace:');
|
self::logError('Stack trace:');
|
||||||
self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4);
|
self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4);
|
||||||
self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues');
|
self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues');
|
||||||
}
|
return self::getReturnCode($e);
|
||||||
|
|
||||||
public static function bindBuilder(?BuilderBase $bind_builder): void
|
|
||||||
{
|
|
||||||
self::$builder = $bind_builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function bindBuildPhpExtraInfo(array $build_php_extra_info): void
|
public static function bindBuildPhpExtraInfo(array $build_php_extra_info): void
|
||||||
@ -182,7 +103,22 @@ class ExceptionHandler
|
|||||||
self::$build_php_extra_info = $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
|
private static function getReturnCode(\Throwable $e): int
|
||||||
|
{
|
||||||
|
return match (get_class($e)) {
|
||||||
|
BuildFailureException::class, ExecutionException::class => BaseCommand::BUILD_ERROR,
|
||||||
|
DownloaderException::class => BaseCommand::DOWNLOAD_ERROR,
|
||||||
|
EnvironmentException::class => BaseCommand::ENVIRONMENT_ERROR,
|
||||||
|
FileSystemException::class => BaseCommand::FILE_SYSTEM_ERROR,
|
||||||
|
InterruptException::class => BaseCommand::INTERRUPT_SIGNAL,
|
||||||
|
PatchException::class => BaseCommand::PATCH_ERROR,
|
||||||
|
ValidationException::class => BaseCommand::VALIDATION_ERROR,
|
||||||
|
WrongUsageException::class => BaseCommand::USER_ERROR,
|
||||||
|
default => BaseCommand::INTERNAL_ERROR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function logError($message, int $indent_space = 0, bool $output_log = true, string $color = 'red'): void
|
||||||
{
|
{
|
||||||
$spc_log = fopen(SPC_OUTPUT_LOG, 'a');
|
$spc_log = fopen(SPC_OUTPUT_LOG, 'a');
|
||||||
$msg = explode("\n", (string) $message);
|
$msg = explode("\n", (string) $message);
|
||||||
@ -190,7 +126,7 @@ class ExceptionHandler
|
|||||||
$line = str_pad($v, strlen($v) + $indent_space, ' ', STR_PAD_LEFT);
|
$line = str_pad($v, strlen($v) + $indent_space, ' ', STR_PAD_LEFT);
|
||||||
fwrite($spc_log, strip_ansi_colors($line) . PHP_EOL);
|
fwrite($spc_log, strip_ansi_colors($line) . PHP_EOL);
|
||||||
if ($output_log) {
|
if ($output_log) {
|
||||||
InteractiveTerm::plain(ConsoleColor::red($line) . '', 'error');
|
InteractiveTerm::plain(ConsoleColor::$color($line) . '', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,4 +165,124 @@ class ExceptionHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function printModuleErrorInfo(SPCException $e): void
|
||||||
|
{
|
||||||
|
$class = get_class($e);
|
||||||
|
self::logError("\n-------------------- " . ConsoleColor::red('Module error info') . ' --------------------', color: 'default');
|
||||||
|
|
||||||
|
$has_info = false;
|
||||||
|
|
||||||
|
// Get Package information
|
||||||
|
if ($package_info = $e->getPackageInfo()) {
|
||||||
|
$type_label = match ($package_info['package_type']) {
|
||||||
|
'library' => 'Library Package',
|
||||||
|
'php-extension' => 'PHP Extension Package',
|
||||||
|
'target' => 'Target Package',
|
||||||
|
default => 'Package',
|
||||||
|
};
|
||||||
|
self::logError('Failed module: ' . ConsoleColor::gray("{$type_label} '{$package_info['package_name']}'"));
|
||||||
|
if ($package_info['file'] && $package_info['line']) {
|
||||||
|
self::logError('Package location: ' . ConsoleColor::gray("{$package_info['file']}:{$package_info['line']}"));
|
||||||
|
}
|
||||||
|
$has_info = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Stage information (can be displayed together with Package info)
|
||||||
|
$stage_stack = $e->getStageStack();
|
||||||
|
if (!empty($stage_stack)) {
|
||||||
|
// Build stage call chain: innermost -> ... -> outermost
|
||||||
|
$stage_names = array_reverse(array_column($stage_stack, 'stage_name'));
|
||||||
|
$stage_chain = implode(' -> ', $stage_names);
|
||||||
|
|
||||||
|
if (count($stage_names) > 1) {
|
||||||
|
self::logError('Failed stage: ' . ConsoleColor::gray($stage_chain));
|
||||||
|
} else {
|
||||||
|
self::logError('Failed stage: ' . ConsoleColor::gray($stage_names[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show context keys of the innermost (actual failing) stage
|
||||||
|
$innermost_stage = $stage_stack[0];
|
||||||
|
if (!empty($innermost_stage['context_keys'])) {
|
||||||
|
self::logError('Stage context keys: ' . ConsoleColor::gray(implode(', ', $innermost_stage['context_keys'])));
|
||||||
|
}
|
||||||
|
$has_info = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get PackageBuilder information
|
||||||
|
if (!$has_info && ($builder_info = $e->getPackageBuilderInfo())) {
|
||||||
|
self::logError('Failed module: ' . ConsoleColor::gray('PackageBuilder'));
|
||||||
|
if ($builder_info['method']) {
|
||||||
|
self::logError('Builder method: ' . ConsoleColor::gray($builder_info['method']));
|
||||||
|
}
|
||||||
|
if ($builder_info['file'] && $builder_info['line']) {
|
||||||
|
self::logError('Builder location: ' . ConsoleColor::gray("{$builder_info['file']}:{$builder_info['line']}"));
|
||||||
|
}
|
||||||
|
$has_info = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get PackageInstaller information
|
||||||
|
if (!$has_info && ($installer_info = $e->getPackageInstallerInfo())) {
|
||||||
|
self::logError('Failed module: ' . ConsoleColor::gray('PackageInstaller'));
|
||||||
|
if ($installer_info['method']) {
|
||||||
|
self::logError('Installer method: ' . ConsoleColor::gray($installer_info['method']));
|
||||||
|
}
|
||||||
|
if ($installer_info['file'] && $installer_info['line']) {
|
||||||
|
self::logError('Installer location: ' . ConsoleColor::gray("{$installer_info['file']}:{$installer_info['line']}"));
|
||||||
|
}
|
||||||
|
$has_info = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$has_info && !in_array($class, self::KNOWN_EXCEPTIONS)) {
|
||||||
|
self::logError('Failed From: ' . ConsoleColor::yellow('Unknown SPC module ' . $class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get command execution info
|
||||||
|
if ($e instanceof ExecutionException) {
|
||||||
|
self::logError('');
|
||||||
|
self::logError('Failed command: ' . ConsoleColor::gray($e->getExecutionCommand()));
|
||||||
|
if ($cd = $e->getCd()) {
|
||||||
|
self::logError(' - Command executed in: ' . ConsoleColor::gray($cd));
|
||||||
|
}
|
||||||
|
if ($env = $e->getEnv()) {
|
||||||
|
self::logError(' - Command inline env variables:');
|
||||||
|
foreach ($env as $k => $v) {
|
||||||
|
self::logError(ConsoleColor::gray("{$k}={$v}"), 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation error
|
||||||
|
if ($e instanceof ValidationException) {
|
||||||
|
self::logError('Failed validation module: ' . ConsoleColor::gray($e->getValidationModuleString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// environment error
|
||||||
|
if ($e instanceof EnvironmentException) {
|
||||||
|
self::logError('Failed environment check: ' . ConsoleColor::gray($e->getMessage()));
|
||||||
|
if (($solution = $e->getSolution()) !== null) {
|
||||||
|
self::logError('Solution: ' . ConsoleColor::gray($solution));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get patch info
|
||||||
|
if ($e instanceof PatchException) {
|
||||||
|
self::logError("Failed patch module: {$e->getPatchModule()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get internal trace
|
||||||
|
if ($e instanceof SPCInternalException) {
|
||||||
|
self::logError('Internal trace:');
|
||||||
|
self::logError(ConsoleColor::gray("{$e->getTraceAsString()}\n"), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the full build info if possible
|
||||||
|
if ($info = ExceptionHandler::$build_php_extra_info) {
|
||||||
|
self::logError('', output_log: ApplicationContext::isDebug());
|
||||||
|
self::logError('Build PHP extra info:', output_log: ApplicationContext::isDebug());
|
||||||
|
self::printArrayInfo($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::logError("---------------------------------------------------------\n", color: 'none');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace StaticPHP\Exception;
|
namespace StaticPHP\Exception;
|
||||||
|
|
||||||
use SPC\util\shell\UnixShell;
|
use StaticPHP\Runtime\Shell\UnixShell;
|
||||||
use SPC\util\shell\WindowsCmd;
|
use StaticPHP\Runtime\Shell\WindowsCmd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when an error occurs during execution of shell command.
|
* Exception thrown when an error occurs during execution of shell command.
|
||||||
|
|||||||
@ -4,12 +4,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace StaticPHP\Exception;
|
namespace StaticPHP\Exception;
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
use StaticPHP\Package\LibraryPackage;
|
||||||
use SPC\builder\freebsd\library\BSDLibraryBase;
|
use StaticPHP\Package\Package;
|
||||||
use SPC\builder\LibraryBase;
|
use StaticPHP\Package\PackageBuilder;
|
||||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
use StaticPHP\Package\PackageInstaller;
|
||||||
use SPC\builder\macos\library\MacOSLibraryBase;
|
use StaticPHP\Package\PhpExtensionPackage;
|
||||||
use SPC\builder\windows\library\WindowsLibraryBase;
|
use StaticPHP\Package\TargetPackage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for SPC exceptions.
|
* Base class for SPC exceptions.
|
||||||
@ -20,11 +20,17 @@ use SPC\builder\windows\library\WindowsLibraryBase;
|
|||||||
*/
|
*/
|
||||||
abstract class SPCException extends \Exception
|
abstract class SPCException extends \Exception
|
||||||
{
|
{
|
||||||
private ?array $library_info = null;
|
/** @var null|array Package information */
|
||||||
|
private ?array $package_info = null;
|
||||||
|
|
||||||
private ?array $extension_info = null;
|
/** @var null|array Package builder information */
|
||||||
|
private ?array $package_builder_info = null;
|
||||||
|
|
||||||
private ?array $build_php_info = null;
|
/** @var null|array Package installer information */
|
||||||
|
private ?array $package_installer_info = null;
|
||||||
|
|
||||||
|
/** @var array Stage execution call stack */
|
||||||
|
private array $stage_stack = [];
|
||||||
|
|
||||||
private array $extra_log_files = [];
|
private array $extra_log_files = [];
|
||||||
|
|
||||||
@ -34,9 +40,38 @@ abstract class SPCException extends \Exception
|
|||||||
$this->loadStackTraceInfo();
|
$this->loadStackTraceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bindExtensionInfo(array $extension_info): void
|
/**
|
||||||
|
* Bind package information manually.
|
||||||
|
*
|
||||||
|
* @param array $package_info Package information array
|
||||||
|
*/
|
||||||
|
public function bindPackageInfo(array $package_info): void
|
||||||
{
|
{
|
||||||
$this->extension_info = $extension_info;
|
$this->package_info = $package_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add stage to the call stack.
|
||||||
|
* This builds a call chain like: build -> configure -> compile
|
||||||
|
*
|
||||||
|
* @param string $stage_name Stage name being executed
|
||||||
|
* @param array $context Stage context (optional)
|
||||||
|
*/
|
||||||
|
public function addStageToStack(string $stage_name, array $context = []): void
|
||||||
|
{
|
||||||
|
$this->stage_stack[] = [
|
||||||
|
'stage_name' => $stage_name,
|
||||||
|
'context_keys' => array_keys($context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy method for backward compatibility.
|
||||||
|
* @deprecated Use addStageToStack() instead
|
||||||
|
*/
|
||||||
|
public function bindStageInfo(string $stage_name, array $context = []): void
|
||||||
|
{
|
||||||
|
$this->addStageToStack($stage_name, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addExtraLogFile(string $key, string $filename): void
|
public function addExtraLogFile(string $key, string $filename): void
|
||||||
@ -45,52 +80,74 @@ abstract class SPCException extends \Exception
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array containing information about the SPC module.
|
* Returns package information.
|
||||||
*
|
|
||||||
* This method can be overridden by subclasses to provide specific module information.
|
|
||||||
*
|
*
|
||||||
* @return null|array{
|
* @return null|array{
|
||||||
* library_name: string,
|
* package_name: string,
|
||||||
* library_class: string,
|
* package_type: string,
|
||||||
* os: string,
|
* package_class: string,
|
||||||
* file: null|string,
|
* file: null|string,
|
||||||
* line: null|int,
|
* line: null|int,
|
||||||
* } an array containing module information
|
* } Package information or null
|
||||||
*/
|
*/
|
||||||
public function getLibraryInfo(): ?array
|
public function getPackageInfo(): ?array
|
||||||
{
|
{
|
||||||
return $this->library_info;
|
return $this->package_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array containing information about the PHP build process.
|
* Returns package builder information.
|
||||||
*
|
*
|
||||||
* @return null|array{
|
* @return null|array{
|
||||||
* builder_function: string,
|
|
||||||
* file: null|string,
|
* file: null|string,
|
||||||
* line: null|int,
|
* line: null|int,
|
||||||
* } an array containing PHP build information
|
* method: null|string,
|
||||||
|
* } Package builder information or null
|
||||||
*/
|
*/
|
||||||
public function getBuildPHPInfo(): ?array
|
public function getPackageBuilderInfo(): ?array
|
||||||
{
|
{
|
||||||
return $this->build_php_info;
|
return $this->package_builder_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array containing information about the SPC extension.
|
* Returns package installer information.
|
||||||
*
|
|
||||||
* This method can be overridden by subclasses to provide specific extension information.
|
|
||||||
*
|
*
|
||||||
* @return null|array{
|
* @return null|array{
|
||||||
* extension_name: string,
|
|
||||||
* extension_class: string,
|
|
||||||
* file: null|string,
|
* file: null|string,
|
||||||
* line: null|int,
|
* line: null|int,
|
||||||
* } an array containing extension information
|
* method: null|string,
|
||||||
|
* } Package installer information or null
|
||||||
*/
|
*/
|
||||||
public function getExtensionInfo(): ?array
|
public function getPackageInstallerInfo(): ?array
|
||||||
{
|
{
|
||||||
return $this->extension_info;
|
return $this->package_installer_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the stage call stack.
|
||||||
|
*
|
||||||
|
* @return array<array{
|
||||||
|
* stage_name: string,
|
||||||
|
* context_keys: array<string>,
|
||||||
|
* }> Stage call stack (empty array if no stages)
|
||||||
|
*/
|
||||||
|
public function getStageStack(): array
|
||||||
|
{
|
||||||
|
return $this->stage_stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the innermost (actual failing) stage information.
|
||||||
|
* Legacy method for backward compatibility.
|
||||||
|
*
|
||||||
|
* @return null|array{
|
||||||
|
* stage_name: string,
|
||||||
|
* context_keys: array<string>,
|
||||||
|
* } Stage information or null
|
||||||
|
*/
|
||||||
|
public function getStageInfo(): ?array
|
||||||
|
{
|
||||||
|
return empty($this->stage_stack) ? null : end($this->stage_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExtraLogFiles(): array
|
public function getExtraLogFiles(): array
|
||||||
@ -98,6 +155,9 @@ abstract class SPCException extends \Exception
|
|||||||
return $this->extra_log_files;
|
return $this->extra_log_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load stack trace information to detect Package, Builder, and Installer context.
|
||||||
|
*/
|
||||||
private function loadStackTraceInfo(): void
|
private function loadStackTraceInfo(): void
|
||||||
{
|
{
|
||||||
$trace = $this->getTrace();
|
$trace = $this->getTrace();
|
||||||
@ -106,40 +166,48 @@ abstract class SPCException extends \Exception
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the class is a subclass of LibraryBase
|
// Check if the class is a Package subclass
|
||||||
if (!$this->library_info && is_a($frame['class'], LibraryBase::class, true)) {
|
if (!$this->package_info && is_a($frame['class'], Package::class, true)) {
|
||||||
try {
|
try {
|
||||||
$reflection = new \ReflectionClass($frame['class']);
|
// Try to get package information from object if available
|
||||||
if ($reflection->hasConstant('NAME')) {
|
if (isset($frame['object']) && $frame['object'] instanceof Package) {
|
||||||
$name = $reflection->getConstant('NAME');
|
$package = $frame['object'];
|
||||||
if ($name !== 'unknown') {
|
$package_type = match (true) {
|
||||||
$this->library_info = [
|
$package instanceof LibraryPackage => 'library',
|
||||||
'library_name' => $name,
|
$package instanceof PhpExtensionPackage => 'php-extension',
|
||||||
'library_class' => $frame['class'],
|
$package instanceof TargetPackage => 'target',
|
||||||
'os' => match (true) {
|
default => 'package',
|
||||||
is_a($frame['class'], BSDLibraryBase::class, true) => 'BSD',
|
};
|
||||||
is_a($frame['class'], LinuxLibraryBase::class, true) => 'Linux',
|
$this->package_info = [
|
||||||
is_a($frame['class'], MacOSLibraryBase::class, true) => 'macOS',
|
'package_name' => $package->name,
|
||||||
is_a($frame['class'], WindowsLibraryBase::class, true) => 'Windows',
|
'package_type' => $package_type,
|
||||||
default => 'Unknown',
|
'package_class' => $frame['class'],
|
||||||
},
|
|
||||||
'file' => $frame['file'] ?? null,
|
'file' => $frame['file'] ?? null,
|
||||||
'line' => $frame['line'] ?? null,
|
'line' => $frame['line'] ?? null,
|
||||||
];
|
];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
} catch (\Throwable) {
|
||||||
} catch (\ReflectionException) {
|
// Ignore reflection errors
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the class is a subclass of BuilderBase and the method is buildPHP
|
// Check if the class is PackageBuilder
|
||||||
if (!$this->build_php_info && is_a($frame['class'], BuilderBase::class, true)) {
|
if (!$this->package_builder_info && is_a($frame['class'], PackageBuilder::class, true)) {
|
||||||
$this->build_php_info = [
|
$this->package_builder_info = [
|
||||||
'builder_function' => $frame['function'],
|
|
||||||
'file' => $frame['file'] ?? null,
|
'file' => $frame['file'] ?? null,
|
||||||
'line' => $frame['line'] ?? null,
|
'line' => $frame['line'] ?? null,
|
||||||
|
'method' => $frame['function'] ?? null,
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the class is PackageInstaller
|
||||||
|
if (!$this->package_installer_info && is_a($frame['class'], PackageInstaller::class, true)) {
|
||||||
|
$this->package_installer_info = [
|
||||||
|
'file' => $frame['file'] ?? null,
|
||||||
|
'line' => $frame['line'] ?? null,
|
||||||
|
'method' => $frame['function'] ?? null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace StaticPHP\Exception;
|
namespace StaticPHP\Exception;
|
||||||
|
|
||||||
use SPC\builder\Extension;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown for validation errors in SPC.
|
* Exception thrown for validation errors in SPC.
|
||||||
*
|
*
|
||||||
@ -23,12 +21,6 @@ class ValidationException extends SPCException
|
|||||||
// init validation module
|
// init validation module
|
||||||
if ($validation_module === null) {
|
if ($validation_module === null) {
|
||||||
foreach ($this->getTrace() as $trace) {
|
foreach ($this->getTrace() as $trace) {
|
||||||
// Extension validate() => "Extension validator"
|
|
||||||
if (is_a($trace['class'] ?? null, Extension::class, true) && $trace['function'] === 'validate') {
|
|
||||||
$this->validation_module = 'Extension validator';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other => "ClassName::functionName"
|
// Other => "ClassName::functionName"
|
||||||
$this->validation_module = [
|
$this->validation_module = [
|
||||||
'class' => $trace['class'] ?? null,
|
'class' => $trace['class'] ?? null,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ namespace StaticPHP\Package;
|
|||||||
use StaticPHP\Artifact\Artifact;
|
use StaticPHP\Artifact\Artifact;
|
||||||
use StaticPHP\Config\PackageConfig;
|
use StaticPHP\Config\PackageConfig;
|
||||||
use StaticPHP\DI\ApplicationContext;
|
use StaticPHP\DI\ApplicationContext;
|
||||||
|
use StaticPHP\Exception\SPCException;
|
||||||
use StaticPHP\Exception\SPCInternalException;
|
use StaticPHP\Exception\SPCInternalException;
|
||||||
use StaticPHP\Registry\ArtifactLoader;
|
use StaticPHP\Registry\ArtifactLoader;
|
||||||
use StaticPHP\Registry\PackageLoader;
|
use StaticPHP\Registry\PackageLoader;
|
||||||
@ -63,6 +64,7 @@ abstract class Package
|
|||||||
static::class => $this,
|
static::class => $this,
|
||||||
], $context);
|
], $context);
|
||||||
|
|
||||||
|
try {
|
||||||
// emit BeforeStage
|
// emit BeforeStage
|
||||||
$this->emitBeforeStage($name, $stageContext);
|
$this->emitBeforeStage($name, $stageContext);
|
||||||
|
|
||||||
@ -70,6 +72,21 @@ abstract class Package
|
|||||||
// emit AfterStage
|
// emit AfterStage
|
||||||
$this->emitAfterStage($name, $stageContext, $ret);
|
$this->emitAfterStage($name, $stageContext, $ret);
|
||||||
return $ret;
|
return $ret;
|
||||||
|
} catch (SPCException $e) {
|
||||||
|
// Bind package information only if not already bound
|
||||||
|
if ($e->getPackageInfo() === null) {
|
||||||
|
$e->bindPackageInfo([
|
||||||
|
'package_name' => $this->name,
|
||||||
|
'package_type' => $this->type,
|
||||||
|
'package_class' => static::class,
|
||||||
|
'file' => null,
|
||||||
|
'line' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// Always add current stage to the stack to build call chain
|
||||||
|
$e->addStageToStack($name, $stageContext);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOutput(string $key, string $value): static
|
public function setOutput(string $key, string $value): static
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace StaticPHP\Package;
|
|||||||
|
|
||||||
use StaticPHP\Config\PackageConfig;
|
use StaticPHP\Config\PackageConfig;
|
||||||
use StaticPHP\DI\ApplicationContext;
|
use StaticPHP\DI\ApplicationContext;
|
||||||
|
use StaticPHP\Exception\SPCException;
|
||||||
use StaticPHP\Exception\SPCInternalException;
|
use StaticPHP\Exception\SPCInternalException;
|
||||||
use StaticPHP\Exception\WrongUsageException;
|
use StaticPHP\Exception\WrongUsageException;
|
||||||
use StaticPHP\Runtime\Shell\Shell;
|
use StaticPHP\Runtime\Shell\Shell;
|
||||||
@ -59,6 +60,7 @@ class PackageBuilder
|
|||||||
InteractiveTerm::advance();
|
InteractiveTerm::advance();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
if ($package->getType() !== 'virtual-target') {
|
if ($package->getType() !== 'virtual-target') {
|
||||||
// patch before build
|
// patch before build
|
||||||
$package->emitPatchBeforeBuild();
|
$package->emitPatchBeforeBuild();
|
||||||
@ -73,6 +75,19 @@ class PackageBuilder
|
|||||||
$this->installLicense($package, $license);
|
$this->installLicense($package, $license);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (SPCException $e) {
|
||||||
|
// Ensure package information is bound if not already
|
||||||
|
if ($e->getPackageInfo() === null) {
|
||||||
|
$e->bindPackageInfo([
|
||||||
|
'package_name' => $package->name,
|
||||||
|
'package_type' => $package->type,
|
||||||
|
'package_class' => get_class($package),
|
||||||
|
'file' => null,
|
||||||
|
'line' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
return SPC_STATUS_BUILT;
|
return SPC_STATUS_BUILT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user