mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-14 04:15:35 +08:00
Refactor all command class exception handling
This commit is contained in:
@@ -4,18 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder;
|
namespace SPC\builder;
|
||||||
|
|
||||||
use PharIo\FileSystem\File;
|
use SPC\exception\BuildFailureException;
|
||||||
use SPC\exception\ExceptionHandler;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\InterruptException;
|
use SPC\exception\InterruptException;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
use SPC\store\SourceManager;
|
use SPC\store\SourceManager;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\AttributeMapper;
|
||||||
|
|
||||||
abstract class BuilderBase
|
abstract class BuilderBase
|
||||||
{
|
{
|
||||||
@@ -64,12 +61,11 @@ abstract class BuilderBase
|
|||||||
match ($status) {
|
match ($status) {
|
||||||
LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'),
|
LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'),
|
||||||
LIB_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
|
LIB_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
|
||||||
LIB_STATUS_BUILD_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
|
|
||||||
LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'),
|
LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'),
|
||||||
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
||||||
};
|
};
|
||||||
if (in_array($status, [LIB_STATUS_BUILD_FAILED, LIB_STATUS_INSTALL_FAILED])) {
|
if (in_array($status, [LIB_STATUS_BUILD_FAILED, LIB_STATUS_INSTALL_FAILED])) {
|
||||||
throw new RuntimeException('Library [' . $lib::NAME . '] setup failed.');
|
throw new BuildFailureException('Library [' . $lib::NAME . '] setup failed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,9 +250,8 @@ abstract class BuilderBase
|
|||||||
}
|
}
|
||||||
$ext->buildShared();
|
$ext->buildShared();
|
||||||
}
|
}
|
||||||
} catch (RuntimeException $e) {
|
} finally {
|
||||||
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
|
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
|
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
|
||||||
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/php/build/phpize.m4', '# test "[$]$1" = "no" && $1=yes', 'test "[$]$1" = "no" && $1=yes');
|
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/php/build/phpize.m4', '# test "[$]$1" = "no" && $1=yes', 'test "[$]$1" = "no" && $1=yes');
|
||||||
@@ -311,7 +306,7 @@ abstract class BuilderBase
|
|||||||
return intval($match[1]);
|
return intval($match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
|
throw new WrongUsageException('PHP version file format is malformed, please remove "./source/php-src" dir and download/extract again');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPHPVersion(bool $exception_on_failure = true): string
|
public function getPHPVersion(bool $exception_on_failure = true): string
|
||||||
@@ -329,7 +324,7 @@ abstract class BuilderBase
|
|||||||
if (!$exception_on_failure) {
|
if (!$exception_on_failure) {
|
||||||
return 'unknown';
|
return 'unknown';
|
||||||
}
|
}
|
||||||
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
|
throw new WrongUsageException('PHP version file format is malformed, please remove it and download again');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -476,7 +471,7 @@ abstract class BuilderBase
|
|||||||
foreach ($patches as $patch) {
|
foreach ($patches as $patch) {
|
||||||
try {
|
try {
|
||||||
if (!file_exists($patch)) {
|
if (!file_exists($patch)) {
|
||||||
throw new RuntimeException("Additional patch script file {$patch} not found!");
|
throw new WrongUsageException("Additional patch script file {$patch} not found!");
|
||||||
}
|
}
|
||||||
logger()->debug('Running additional patch script: ' . $patch);
|
logger()->debug('Running additional patch script: ' . $patch);
|
||||||
require $patch;
|
require $patch;
|
||||||
@@ -489,11 +484,6 @@ abstract class BuilderBase
|
|||||||
exit($e->getCode());
|
exit($e->getCode());
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
logger()->critical('Patch script ' . $patch . ' failed to run.');
|
logger()->critical('Patch script ' . $patch . ' failed to run.');
|
||||||
if ($this->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use Laravel\Prompts\Prompt;
|
|||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
use SPC\ConsoleApplication;
|
use SPC\ConsoleApplication;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\ValidationException;
|
use SPC\exception\SPCException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\util\AttributeMapper;
|
||||||
use SPC\util\GlobalEnvManager;
|
use SPC\util\GlobalEnvManager;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||||
@@ -32,6 +32,7 @@ abstract class BaseCommand extends Command
|
|||||||
parent::__construct($name);
|
parent::__construct($name);
|
||||||
$this->addOption('debug', null, null, 'Enable debug mode');
|
$this->addOption('debug', null, null, 'Enable debug mode');
|
||||||
$this->addOption('no-motd', null, null, 'Disable motd');
|
$this->addOption('no-motd', null, null, 'Disable motd');
|
||||||
|
$this->addOption('preserve-log', null, null, 'Preserve log files, do not delete them on initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||||
@@ -93,31 +94,21 @@ abstract class BaseCommand extends Command
|
|||||||
GlobalEnvManager::init();
|
GlobalEnvManager::init();
|
||||||
f_putenv('SPC_SKIP_TOOLCHAIN_CHECK=yes');
|
f_putenv('SPC_SKIP_TOOLCHAIN_CHECK=yes');
|
||||||
}
|
}
|
||||||
if ($this->shouldExecute()) {
|
|
||||||
try {
|
try {
|
||||||
// show raw argv list for logger()->debug
|
// show raw argv list for logger()->debug
|
||||||
logger()->debug('argv: ' . implode(' ', $_SERVER['argv']));
|
logger()->debug('argv: ' . implode(' ', $_SERVER['argv']));
|
||||||
return $this->handle();
|
return $this->handle();
|
||||||
} catch (ValidationException|WrongUsageException $e) {
|
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (SPCException $e) {
|
||||||
$msg = explode("\n", $e->getMessage());
|
// Handle SPCException and log it
|
||||||
foreach ($msg as $v) {
|
ExceptionHandler::handleSPCException($e);
|
||||||
logger()->error($v);
|
|
||||||
}
|
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if ($this->getOption('debug')) {
|
// Handle any other exceptions
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
ExceptionHandler::handleDefaultException($e);
|
||||||
} else {
|
|
||||||
$msg = explode("\n", $e->getMessage());
|
|
||||||
foreach ($msg as $v) {
|
|
||||||
logger()->error($v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return static::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getOption(string $name): mixed
|
protected function getOption(string $name): mixed
|
||||||
{
|
{
|
||||||
@@ -129,11 +120,6 @@ abstract class BaseCommand extends Command
|
|||||||
return $this->input->getArgument($name);
|
return $this->input->getArgument($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function shouldExecute(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function logWithResult(bool $result, string $success_msg, string $fail_msg): int
|
protected function logWithResult(bool $result, string $success_msg, string $fail_msg): int
|
||||||
{
|
{
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ class BuildLibsCommand extends BuildCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
// 构建对象
|
// 构建对象
|
||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
// 只编译 library 的情况下,标记
|
// 只编译 library 的情况下,标记
|
||||||
@@ -68,14 +67,5 @@ class BuildLibsCommand extends BuildCommand
|
|||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($this->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\SPCException;
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
@@ -119,7 +118,6 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
logger()->warning('Some cases micro.sfx cannot be packed via UPX due to dynamic size bug, be aware!');
|
logger()->warning('Some cases micro.sfx cannot be packed via UPX due to dynamic size bug, be aware!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
// create builder
|
// create builder
|
||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||||
@@ -167,6 +165,8 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
}
|
}
|
||||||
$this->printFormatInfo($this->getDefinedEnvs(), true);
|
$this->printFormatInfo($this->getDefinedEnvs(), true);
|
||||||
$this->printFormatInfo($indent_texts);
|
$this->printFormatInfo($indent_texts);
|
||||||
|
// bind extra info to SPCException
|
||||||
|
SPCException::bindBuildPHPExtraInfo($indent_texts);
|
||||||
|
|
||||||
logger()->notice('Build will start after 2s ...');
|
logger()->notice('Build will start after 2s ...');
|
||||||
sleep(2);
|
sleep(2);
|
||||||
@@ -266,20 +266,6 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
$path = FileSystem::convertPath("{$build_root_path}/license/");
|
$path = FileSystem::convertPath("{$build_root_path}/license/");
|
||||||
logger()->info("License path{$fixed}: {$path}");
|
logger()->info("License path{$fixed}: {$path}");
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (WrongUsageException $e) {
|
|
||||||
// WrongUsageException is not an exception, it's a user error, so we just print the error message
|
|
||||||
logger()->critical($e->getMessage());
|
|
||||||
logger()->error($e->getTraceAsString());
|
|
||||||
return static::FAILURE;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($this->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
use SPC\exception\DownloaderException;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Downloader;
|
use SPC\store\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
@@ -36,7 +33,6 @@ class DeleteDownloadCommand extends BaseCommand
|
|||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
// get source list that will be downloaded
|
// get source list that will be downloaded
|
||||||
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||||
if (empty($sources)) {
|
if (empty($sources)) {
|
||||||
@@ -81,12 +77,5 @@ class DeleteDownloadCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
logger()->info('Delete success!');
|
logger()->info('Delete success!');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (DownloaderException $e) {
|
|
||||||
logger()->error($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
} catch (WrongUsageException $e) {
|
|
||||||
logger()->critical($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ namespace SPC\command;
|
|||||||
|
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\SPCException;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\Downloader;
|
use SPC\store\Downloader;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
@@ -87,7 +85,6 @@ class DownloadCommand extends BaseCommand
|
|||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
if ($this->getOption('clean')) {
|
if ($this->getOption('clean')) {
|
||||||
return $this->_clean();
|
return $this->_clean();
|
||||||
}
|
}
|
||||||
@@ -227,7 +224,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
|
||||||
try {
|
try {
|
||||||
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
||||||
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (DownloaderException|RuntimeException $e) {
|
} catch (SPCException $e) {
|
||||||
// if `--no-alt` option is set, we will not download alternative sources
|
// if `--no-alt` option is set, we will not download alternative sources
|
||||||
if ($this->getOption('no-alt')) {
|
if ($this->getOption('no-alt')) {
|
||||||
throw $e;
|
throw $e;
|
||||||
@@ -251,13 +248,6 @@ class DownloadCommand extends BaseCommand
|
|||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
logger()->info('Download complete, used ' . $time . ' s !');
|
logger()->info('Download complete, used ' . $time . ' s !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (DownloaderException $e) {
|
|
||||||
logger()->error($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
} catch (WrongUsageException $e) {
|
|
||||||
logger()->critical($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function downloadFromZip(string $path): int
|
private function downloadFromZip(string $path): int
|
||||||
@@ -276,28 +266,24 @@ class DownloadCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
// unzip command check
|
// unzip command check
|
||||||
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
|
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
|
||||||
logger()->critical('Missing unzip command, you need to install it first !');
|
$this->output->writeln('Missing unzip command, you need to install it first !');
|
||||||
logger()->critical('You can use "bin/spc doctor" command to check and install required tools');
|
$this->output->writeln('You can use "bin/spc doctor" command to check and install required tools');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
// create downloads
|
// create downloads
|
||||||
try {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
if (PHP_OS_FAMILY !== 'Windows') {
|
|
||||||
$abs_path = realpath($path);
|
|
||||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
|
||||||
} else {
|
|
||||||
// Windows TODO
|
// Windows TODO
|
||||||
throw new WrongUsageException('Windows currently does not support --from-zip !');
|
$this->output->writeln('<error>Windows currently does not support --from-zip !</error>');
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_exists(LockFile::LOCK_FILE)) {
|
|
||||||
throw new RuntimeException('.lock.json not exist in "downloads/"');
|
|
||||||
}
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
logger()->critical('Extract failed: ' . $e->getMessage());
|
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
logger()->info('Extract success');
|
$abs_path = realpath($path);
|
||||||
|
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
||||||
|
|
||||||
|
if (!file_exists(LockFile::LOCK_FILE)) {
|
||||||
|
$this->output->writeln('<error>.lock.json not exist in "downloads/", please run "bin/spc download" first !</error>');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
$this->output->writeln('<info>Extract success</info>');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
use SPC\exception\DownloaderException;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\PackageManager;
|
use SPC\store\PackageManager;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
@@ -30,7 +27,6 @@ class InstallPkgCommand extends BaseCommand
|
|||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
// Use shallow-clone can reduce git resource download
|
// Use shallow-clone can reduce git resource download
|
||||||
if ($this->getOption('shallow-clone')) {
|
if ($this->getOption('shallow-clone')) {
|
||||||
define('GIT_SHALLOW_CLONE', true);
|
define('GIT_SHALLOW_CLONE', true);
|
||||||
@@ -84,12 +80,5 @@ class InstallPkgCommand extends BaseCommand
|
|||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
logger()->info('Install packages complete, used ' . $time . ' s !');
|
logger()->info('Install packages complete, used ' . $time . ' s !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (DownloaderException $e) {
|
|
||||||
logger()->error($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
} catch (WrongUsageException $e) {
|
|
||||||
logger()->critical($e->getMessage());
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ namespace SPC\command\dev;
|
|||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\builder\LibraryBase;
|
use SPC\builder\LibraryBase;
|
||||||
use SPC\command\BuildCommand;
|
use SPC\command\BuildCommand;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ValidationException;
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
@@ -30,7 +27,6 @@ class PackLibCommand extends BuildCommand
|
|||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
$lib_name = $this->getArgument('library');
|
$lib_name = $this->getArgument('library');
|
||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
$builder->setLibsOnly();
|
$builder->setLibsOnly();
|
||||||
@@ -135,15 +131,6 @@ class PackLibCommand extends BuildCommand
|
|||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($this->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sanityCheckLib(LibraryBase $lib): void
|
private function sanityCheckLib(LibraryBase $lib): void
|
||||||
@@ -152,7 +139,10 @@ class PackLibCommand extends BuildCommand
|
|||||||
// config
|
// config
|
||||||
foreach ($lib->getStaticLibs() as $static_lib) {
|
foreach ($lib->getStaticLibs() as $static_lib) {
|
||||||
if (!file_exists(FileSystem::convertPath(BUILD_LIB_PATH . '/' . $static_lib))) {
|
if (!file_exists(FileSystem::convertPath(BUILD_LIB_PATH . '/' . $static_lib))) {
|
||||||
throw new RuntimeException('Static library ' . $static_lib . ' not found in ' . BUILD_LIB_PATH);
|
throw new ValidationException(
|
||||||
|
'Static library ' . $static_lib . ' not found in ' . BUILD_LIB_PATH,
|
||||||
|
validation_module: "Static library {$static_lib} existence check"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,167 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
|
use ZM\Logger\ConsoleColor;
|
||||||
|
|
||||||
class ExceptionHandler
|
class ExceptionHandler
|
||||||
{
|
{
|
||||||
protected mixed $whoops = null;
|
public const array KNOWN_EXCEPTIONS = [
|
||||||
|
BuildFailureException::class,
|
||||||
|
DownloaderException::class,
|
||||||
|
EnvironmentException::class,
|
||||||
|
ExecutionException::class,
|
||||||
|
FileSystemException::class,
|
||||||
|
InterruptException::class,
|
||||||
|
PatchException::class,
|
||||||
|
SPCInternalException::class,
|
||||||
|
ValidationException::class,
|
||||||
|
WrongUsageException::class,
|
||||||
|
];
|
||||||
|
|
||||||
private static ?ExceptionHandler $obj = null;
|
public const array MINOR_LOG_EXCEPTIONS = [
|
||||||
|
InterruptException::class,
|
||||||
|
WrongUsageException::class,
|
||||||
|
];
|
||||||
|
|
||||||
public static function getInstance(): ExceptionHandler
|
public static function handleSPCException(SPCException $e): void
|
||||||
{
|
{
|
||||||
if (self::$obj === null) {
|
// XXX error: yyy
|
||||||
self::$obj = new self();
|
$head_msg = match ($class = get_class($e)) {
|
||||||
}
|
BuildFailureException::class => "Build failed: {$e->getMessage()}",
|
||||||
return self::$obj;
|
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()}",
|
||||||
|
WrongUsageException::class => $e->getMessage(),
|
||||||
|
default => "Unknown SPC exception {$class}: {$e->getMessage()}",
|
||||||
|
};
|
||||||
|
self::logError($head_msg);
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
$minor_logs = in_array($class, self::MINOR_LOG_EXCEPTIONS, true);
|
||||||
|
|
||||||
|
if ($minor_logs) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(\Throwable $e): void
|
self::logError("----------------------------------------\n");
|
||||||
|
|
||||||
|
// 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']}"));
|
||||||
|
} elseif ($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 (!in_array($class, self::KNOWN_EXCEPTIONS)) {
|
||||||
|
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()));
|
||||||
|
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 = $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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::logError("\n----------------------------------------\n");
|
||||||
|
|
||||||
|
// put getenv info to log
|
||||||
|
$env_log = fopen(SPC_ENV_LOG, 'a');
|
||||||
|
$env_info = getenv();
|
||||||
|
if ($env_info) {
|
||||||
|
foreach ($env_info as $k => $v) {
|
||||||
|
fwrite($env_log, $k . ' = ' . $v . PHP_EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::logError('⚠ The ' . ConsoleColor::cyan('console output log') . ConsoleColor::red(' is saved in ') . ConsoleColor::none(SPC_OUTPUT_LOG));
|
||||||
|
if (file_exists(SPC_SHELL_LOG)) {
|
||||||
|
self::logError('⚠ The ' . ConsoleColor::cyan('shell output log') . ConsoleColor::red(' is saved in ') . ConsoleColor::none(SPC_SHELL_LOG));
|
||||||
|
}
|
||||||
|
if ($e->getExtraLogFiles() !== []) {
|
||||||
|
foreach ($e->getExtraLogFiles() as $key => $file) {
|
||||||
|
self::logError("⚠ Log file [{$key}] is saved in: " . ConsoleColor::none(SPC_LOGS_DIR . "/{$file}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!defined('DEBUG_MODE')) {
|
||||||
|
self::logError('⚠ If you want to see more details in console, use `--debug` option.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function handleDefaultException(\Throwable $e): void
|
||||||
{
|
{
|
||||||
logger()->error('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')');
|
$class = get_class($e);
|
||||||
logger()->error($e->getTraceAsString());
|
self::logError("Unhandled exception {$class}: {$e->getMessage()}\n\t{$e->getMessage()}\n");
|
||||||
logger()->critical('You can report this exception to static-php-cli GitHub repo.');
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function logError($message, int $indent_space = 0): 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use SPC\builder\BuilderBase;
|
|||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
use SPC\builder\LibraryBase;
|
use SPC\builder\LibraryBase;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
@@ -88,7 +87,7 @@ class BuilderTest extends TestCase
|
|||||||
if ($cnt !== 0) {
|
if ($cnt !== 0) {
|
||||||
$this->assertEquals(intval($match[1]), $this->builder->getPHPVersionID());
|
$this->assertEquals(intval($match[1]), $this->builder->getPHPVersionID());
|
||||||
} else {
|
} else {
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(WrongUsageException::class);
|
||||||
$this->builder->getPHPVersionID();
|
$this->builder->getPHPVersionID();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -105,7 +104,7 @@ class BuilderTest extends TestCase
|
|||||||
if ($cnt !== 0) {
|
if ($cnt !== 0) {
|
||||||
$this->assertEquals($match[1], $this->builder->getPHPVersion());
|
$this->assertEquals($match[1], $this->builder->getPHPVersion());
|
||||||
} else {
|
} else {
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(WrongUsageException::class);
|
||||||
$this->builder->getPHPVersion();
|
$this->builder->getPHPVersion();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -246,7 +245,7 @@ class BuilderTest extends TestCase
|
|||||||
public function testEmitPatchPointNotExists()
|
public function testEmitPatchPointNotExists()
|
||||||
{
|
{
|
||||||
$this->expectOutputRegex('/failed to run/');
|
$this->expectOutputRegex('/failed to run/');
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(WrongUsageException::class);
|
||||||
$this->builder->setOption('with-added-patch', ['/tmp/patch-point.not_exsssists.php']);
|
$this->builder->setOption('with-added-patch', ['/tmp/patch-point.not_exsssists.php']);
|
||||||
$this->builder->emitPatchPoint('not-exists');
|
$this->builder->emitPatchPoint('not-exists');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user