Refactor all (except command) modules using new exceptions

This commit is contained in:
crazywhalecc
2025-08-06 20:43:23 +08:00
committed by Jerry Ma
parent 722bb31815
commit f68f060be2
47 changed files with 335 additions and 291 deletions

View File

@@ -4,8 +4,9 @@ declare(strict_types=1);
namespace SPC\builder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\EnvironmentException;
use SPC\exception\SPCException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
@@ -30,10 +31,10 @@ class Extension
$unix_only = Config::getExt($this->name, 'unix-only', false);
$windows_only = Config::getExt($this->name, 'windows-only', false);
if (PHP_OS_FAMILY !== 'Windows' && $windows_only) {
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Linux and macOS platform");
throw new EnvironmentException("{$ext_type} extension {$name} is not supported on Linux and macOS platform");
}
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
throw new EnvironmentException("{$ext_type} extension {$name} is not supported on Windows platform");
}
// set source_dir for builtin
if ($ext_type === 'builtin') {
@@ -41,7 +42,7 @@ class Extension
} elseif ($ext_type === 'external') {
$source = Config::getExt($this->name, 'source');
if ($source === null) {
throw new RuntimeException("{$ext_type} extension {$name} source not found");
throw new ValidationException("{$ext_type} extension {$name} source not found", validation_module: "Extension [{$name}] loader");
}
$source_path = Config::getSource($source)['path'] ?? null;
$source_path = $source_path === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $source_path;
@@ -287,13 +288,12 @@ class Extension
{
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
// If check failed, throw RuntimeException
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
if ($ret !== 0) {
throw new RuntimeException(
'extension ' . $this->getName() . ' failed runtime check: php-cli returned ' . $ret . "\n" .
join("\n", $out)
throw new ValidationException(
"extension {$this->getName()} failed compile check: php-cli returned {$ret}",
validation_module: 'Extension ' . $this->getName() . ' sanity check'
);
}
@@ -307,8 +307,10 @@ class Extension
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' -r "' . trim($test) . '"');
if ($ret !== 0) {
var_dump($out);
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
throw new ValidationException(
"extension {$this->getName()} failed sanity check. Code: {$ret}, output: " . implode("\n", $out),
validation_module: 'Extension ' . $this->getName() . ' function check'
);
}
}
}
@@ -317,10 +319,9 @@ class Extension
{
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
// If check failed, throw RuntimeException
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -n --ri "' . $this->getDistName() . '"', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: "Extension {$this->getName()} sanity check");
}
if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php'))) {
@@ -333,7 +334,10 @@ class Extension
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -n -r "' . trim($test) . '"');
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
throw new ValidationException(
"extension {$this->getName()} failed function check",
validation_module: "Extension {$this->getName()} function check"
);
}
}
}
@@ -348,34 +352,39 @@ class Extension
*/
public function buildShared(): void
{
if (Config::getExt($this->getName(), 'type') === 'builtin' || Config::getExt($this->getName(), 'build-with-php') === true) {
try {
if (Config::getExt($this->getName(), 'type') === 'builtin' || Config::getExt($this->getName(), 'build-with-php') === true) {
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built by php-src/configure (' . $this->getName() . '.so)');
return;
}
if (Config::getExt($this->getName(), 'build-with-php') === true) {
logger()->warning('Shared extension [' . $this->getName() . '] did not build with php-src/configure (' . $this->getName() . '.so)');
logger()->warning('Try deleting your build and source folders and running `spc build`` again.');
return;
}
}
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built by php-src/configure (' . $this->getName() . '.so)');
return;
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
}
if (Config::getExt($this->getName(), 'build-with-php') === true) {
logger()->warning('Shared extension [' . $this->getName() . '] did not build with php-src/configure (' . $this->getName() . '.so)');
logger()->warning('Try deleting your build and source folders and running `spc build`` again.');
return;
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
continue;
}
if (!$dependency->isBuildStatic()) {
logger()->info('extension ' . $this->getName() . ' requires extension ' . $dependency->getName());
$dependency->buildShared();
}
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
};
} catch (SPCException $e) {
$e->bindExtensionInfo(['extension_name' => $this->getName()]);
throw $e;
}
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
continue;
}
if (!$dependency->isBuildStatic()) {
logger()->info('extension ' . $this->getName() . ' requires extension ' . $dependency->getName());
$dependency->buildShared();
}
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
};
}
/**
@@ -479,7 +488,7 @@ class Extension
$depLib = $this->builder->getLib($name);
if (!$depLib) {
if (!$optional) {
throw new RuntimeException("extension {$this->name} requires library {$name}");
throw new WrongUsageException("extension {$this->name} requires library {$name}");
}
logger()->info("enabling {$this->name} without library {$name}");
} else {
@@ -492,7 +501,7 @@ class Extension
$depExt = $this->builder->getExt($name);
if (!$depExt) {
if (!$optional) {
throw new RuntimeException("{$this->name} requires extension {$name}");
throw new WrongUsageException("{$this->name} requires extension {$name} which is not included");
}
logger()->info("enabling {$this->name} without extension {$name}");
} else {

View File

@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace SPC\builder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\SPCException;
use SPC\exception\SPCInternalException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\Downloader;
@@ -30,9 +30,9 @@ abstract class LibraryBase
public function __construct(?string $source_dir = null)
{
if (static::NAME === 'unknown') {
throw new RuntimeException('no unknown!!!!!');
throw new SPCInternalException('Please set the NAME constant in ' . static::class);
}
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . Config::getLib(static::NAME, 'source'));
$this->source_dir = $source_dir ?? (SOURCE_PATH . DIRECTORY_SEPARATOR . Config::getLib(static::NAME, 'source'));
}
/**
@@ -154,7 +154,7 @@ abstract class LibraryBase
FileSystem::extractPackage($install_file, $lock['source_type'], DOWNLOAD_PATH . '/' . $install_file, BUILD_ROOT_PATH);
$this->install();
return LIB_STATUS_OK;
} catch (FileSystemException|RuntimeException $e) {
} catch (SPCException $e) {
logger()->error('Failed to extract pre-built library [' . static::NAME . ']: ' . $e->getMessage());
return LIB_STATUS_INSTALL_FAILED;
}
@@ -304,7 +304,7 @@ abstract class LibraryBase
}
$replace_items = json_decode(file_get_contents($replace_item_file), true);
if (!is_array($replace_items)) {
throw new RuntimeException('Invalid placeholder file: ' . $replace_item_file);
throw new SPCInternalException("Invalid placeholder file: {$replace_item_file}");
}
$placeholders = get_pack_replace();
// replace placeholders in BUILD_ROOT_PATH
@@ -331,7 +331,7 @@ abstract class LibraryBase
return;
}
if (!$optional) {
throw new RuntimeException(static::NAME . " requires library {$name}");
throw new WrongUsageException(static::NAME . " requires library {$name} but it is not included");
}
logger()->debug('enabling ' . static::NAME . " without {$name}");
}

View File

@@ -8,8 +8,7 @@ use SPC\builder\Extension;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\macos\MacOSBuilder;
use SPC\builder\windows\WindowsBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\exception\PatchException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
@@ -98,7 +97,7 @@ class curl extends Extension
);
if ($patched === null) {
throw new \RuntimeException('Failed to patch config.m4 due to a regex error');
throw new PatchException('shared extension curl patcher', 'Failed to patch config.m4 due to a regex error');
}
FileSystem::writeFile($file, $patched);

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\windows\WindowsBuilder;
use SPC\exception\ValidationException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\GlobalEnvManager;
@@ -18,7 +19,7 @@ class grpc extends Extension
public function patchBeforeBuildconf(): bool
{
if ($this->builder instanceof WindowsBuilder) {
throw new \RuntimeException('grpc extension does not support windows yet');
throw new ValidationException('grpc extension does not support windows yet');
}
if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) {
return false;
@@ -27,7 +28,7 @@ class grpc extends Extension
if (is_dir($this->source_dir . '/src/php/ext/grpc')) {
shell()->exec('ln -s ' . $this->source_dir . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc');
} else {
throw new \RuntimeException('Cannot find grpc source code');
throw new ValidationException('Cannot find grpc source code in ' . $this->source_dir . '/src/php/ext/grpc');
}
if (SPCTarget::getTargetOS() === 'Darwin') {
FileSystem::replaceFileRegex(

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\util\CustomExt;
#[CustomExt('mbregex')]
@@ -16,11 +16,6 @@ class mbregex extends Extension
return 'mbstring';
}
public function getConfigureArg(bool $shared = false): string
{
return '';
}
/**
* mbregex is not an extension, we need to overwrite the default check.
*/
@@ -29,7 +24,7 @@ class mbregex extends Extension
$sharedext = $this->builder->getExt('mbstring')->isBuildShared() ? '-d "extension_dir=' . BUILD_MODULES_PATH . '" -d "extension=mbstring"' : '';
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $sharedext . ' --ri "mbstring" | grep regex', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
throw new ValidationException("Extension {$this->getName()} failed compile check: compiled php-cli mbstring extension does not contain regex !");
}
}
@@ -37,11 +32,11 @@ class mbregex extends Extension
{
[$ret, $out] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "mbstring"', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli does not contain mbstring !');
throw new ValidationException("extension {$this->getName()} failed compile check: compiled php-cli does not contain mbstring !");
}
$out = implode("\n", $out);
if (!str_contains($out, 'regex')) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
throw new ValidationException("extension {$this->getName()} failed compile check: compiled php-cli mbstring extension does not contain regex !");
}
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\ValidationException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\GlobalEnvManager;
@@ -15,7 +16,7 @@ class opentelemetry extends Extension
public function validate(): void
{
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new \RuntimeException('The opentelemetry extension requires PHP 8.0 or later');
throw new ValidationException('The opentelemetry extension requires PHP 8.0 or later');
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\util\CustomExt;
#[CustomExt('password-argon2')]
@@ -20,7 +20,7 @@ class password_argon2 extends Extension
{
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "assert(defined(\'PASSWORD_ARGON2I\'));"');
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
throw new ValidationException('extension ' . $this->getName() . ' failed sanity check', validation_module: 'password_argon2 function check');
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\ValidationException;
use SPC\util\CustomExt;
#[CustomExt('protobuf')]
@@ -13,12 +14,12 @@ class protobuf extends Extension
public function validate(): void
{
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new \RuntimeException('The latest protobuf extension requires PHP 8.0 or later');
throw new ValidationException('The latest protobuf extension requires PHP 8.0 or later');
}
$grpc = $this->builder->getExt('grpc');
// protobuf conflicts with grpc
if ($grpc?->isBuildStatic()) {
throw new \RuntimeException('protobuf conflicts with grpc, please remove grpc or protobuf extension');
throw new ValidationException('protobuf conflicts with grpc, please remove grpc or protobuf extension');
}
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\util\CustomExt;
#[CustomExt('swoole-hook-mysql')]
@@ -32,10 +32,10 @@ class swoole_hook_mysql extends Extension
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $this->getSharedExtensionLoadString() . ' --ri "swoole"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: 'extension swoole_hook_mysql sanity check');
}
if (!str_contains($out, 'mysqlnd')) {
throw new RuntimeException('swoole mysql hook is not enabled correctly.');
throw new ValidationException('swoole mysql hook is not enabled correctly.', validation_module: 'Extension swoole mysql hook avilability check');
}
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\util\CustomExt;
@@ -41,10 +41,16 @@ class swoole_hook_pgsql extends Extension
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
throw new ValidationException(
"extension {$this->getName()} failed sanity check: php-cli returned {$ret}",
validation_module: 'Extension swoole-hook-pgsql sanity check'
);
}
if (!str_contains($out, 'coroutine_pgsql')) {
throw new RuntimeException('swoole pgsql hook is not enabled correctly.');
throw new ValidationException(
'swoole pgsql hook is not enabled correctly.',
validation_module: 'Extension swoole pgsql hook availability check'
);
}
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\util\CustomExt;
@@ -41,10 +41,10 @@ class swoole_hook_sqlite extends Extension
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: "Extension {$this->getName()} sanity check");
}
if (!str_contains($out, 'coroutine_sqlite')) {
throw new RuntimeException('swoole sqlite hook is not enabled correctly.');
throw new ValidationException('swoole sqlite hook is not enabled correctly.', validation_module: 'Extension swoole sqlite hook availability check');
}
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\ValidationException;
use SPC\util\CustomExt;
#[CustomExt('swow')]
@@ -14,7 +14,7 @@ class swow extends Extension
public function validate(): void
{
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new RuntimeException('The latest swow extension requires PHP 8.0 or later');
throw new ValidationException('The latest swow extension requires PHP 8.0 or later');
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\ValidationException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
@@ -14,7 +15,7 @@ class uv extends Extension
public function validate(): void
{
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new \RuntimeException('The latest uv extension requires PHP 8.0 or later');
throw new ValidationException('The latest uv extension requires PHP 8.0 or later');
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\exception\SPCInternalException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
@@ -24,7 +24,7 @@ class xml extends Extension
'xmlreader' => '--enable-xmlreader',
'xmlwriter' => '--enable-xmlwriter',
'simplexml' => '--enable-simplexml',
default => throw new RuntimeException('Not accept non-xml extension'),
default => throw new SPCInternalException('Not accept non-xml extension'),
};
$arg .= ($shared ? '=shared' : '') . ' --with-libxml="' . BUILD_ROOT_PATH . '"';
return $arg;
@@ -44,7 +44,7 @@ class xml extends Extension
'xmlreader' => '--enable-xmlreader',
'xmlwriter' => '--enable-xmlwriter',
'simplexml' => '--with-simplexml',
default => throw new RuntimeException('Not accept non-xml extension'),
default => throw new SPCInternalException('Not accept non-xml extension'),
};
$arg .= ' --with-libxml';
return $arg;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\freebsd;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\RuntimeException;
use SPC\exception\EnvironmentException;
use SPC\exception\WrongUsageException;
class SystemUtil
@@ -20,7 +20,10 @@ class SystemUtil
{
[$ret, $output] = shell()->execWithResult('sysctl -n hw.ncpu');
if ($ret !== 0) {
throw new RuntimeException('Failed to get cpu count');
throw new EnvironmentException(
'Failed to get cpu count from FreeBSD sysctl',
'Please ensure you are running this command on a FreeBSD system and have the sysctl command available.'
);
}
return (int) $output[0];

View File

@@ -358,7 +358,7 @@ class LinuxBuilder extends UnixBuilderBase
$out[1] = explode(' ', $out[1]);
$offset = $out[1][0];
if ($ret !== 0 || !str_starts_with($offset, '0x')) {
throw new RuntimeException('Cannot find offset in readelf output');
throw new PatchException('phpmicro UPX patcher', 'Cannot find offset in readelf output');
}
$offset = hexdec($offset);
// remove upx extra wastes

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\macos;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\RuntimeException;
use SPC\exception\EnvironmentException;
use SPC\exception\WrongUsageException;
class SystemUtil
@@ -18,12 +18,15 @@ class SystemUtil
*/
public static function getCpuCount(): int
{
[$ret, $output] = shell()->execWithResult('sysctl -n hw.ncpu', false);
$cpu = exec('sysctl -n hw.ncpu', $output, $ret);
if ($ret !== 0) {
throw new RuntimeException('Failed to get cpu count');
throw new EnvironmentException(
'Failed to get cpu count from macOS sysctl',
'Please ensure you are running this command on a macOS system and have the sysctl command available.'
);
}
return (int) $output[0];
return (int) $cpu;
}
/**

View File

@@ -4,9 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\traits;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\exception\PatchException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\util\SPCConfigUtil;
@@ -38,7 +36,7 @@ trait UnixLibraryTrait
foreach ($files as $name) {
$realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name);
if ($realpath === false) {
throw new RuntimeException('Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] !');
throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !');
}
logger()->debug('Patching ' . $realpath);
// replace prefix
@@ -65,7 +63,7 @@ trait UnixLibraryTrait
$realpath = realpath(BUILD_LIB_PATH . '/' . $name);
if ($realpath === false) {
if ($throwOnMissing) {
throw new RuntimeException('Cannot find library [' . static::NAME . '] la file [' . $name . '] !');
throw new PatchException('la dependency patcher', 'Cannot find library [' . static::NAME . '] la file [' . $name . '] !');
}
logger()->warning('Cannot find library [' . static::NAME . '] la file [' . $name . '] !');
continue;

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\traits;
use SPC\exception\RuntimeException;
use SPC\exception\SPCException;
use SPC\store\FileSystem;
use SPC\util\PkgConfigUtil;
@@ -24,7 +24,7 @@ trait openssl
if (PHP_OS_FAMILY !== 'Windows') {
try {
return PkgConfigUtil::getModuleVersion('openssl');
} catch (RuntimeException) {
} catch (SPCException) {
}
}
// get openssl version from header openssl/opensslv.h

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace SPC\builder\unix;
use SPC\builder\BuilderBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\SPCInternalException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\CurlHook;
@@ -56,7 +56,14 @@ abstract class UnixBuilderBase extends BuilderBase
}
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
$os = match (PHP_OS_FAMILY) {
'Linux' => 'Linux',
'Darwin' => 'macOS',
'Windows' => 'Windows',
'BSD' => 'FreeBSD',
default => PHP_OS_FAMILY,
};
throw new WrongUsageException("library [{$library}] is in the lib.json list but not supported to build on {$os}.");
}
$lib = new ($support_lib_list[$library])($this);
$this->addLib($lib);
@@ -80,7 +87,7 @@ abstract class UnixBuilderBase extends BuilderBase
[$ret, $output] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -r "echo \"hello\";"');
$raw_output = implode('', $output);
if ($ret !== 0 || trim($raw_output) !== 'hello') {
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
throw new ValidationException("cli failed sanity check. code: {$ret}, output: {$raw_output}", validation_module: 'php-cli sanity check');
}
foreach ($this->getExts() as $ext) {
@@ -103,7 +110,10 @@ abstract class UnixBuilderBase extends BuilderBase
foreach ($task['conditions'] as $condition => $closure) {
if (!$closure($ret, $out)) {
$raw_out = trim(implode('', $out));
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
throw new ValidationException(
"failure info: {$condition}, code: {$ret}, output: {$raw_out}",
validation_module: "phpmicro sanity check item [{$task_name}]"
);
}
}
}
@@ -142,11 +152,17 @@ abstract class UnixBuilderBase extends BuilderBase
}
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
if ($ret !== 0) {
throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out));
throw new ValidationException(
'embed failed sanity check: build failed. Error message: ' . implode("\n", $out),
validation_module: 'static libphp.a sanity check'
);
}
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output));
throw new ValidationException(
'embed failed sanity check: run failed. Error message: ' . implode("\n", $output),
validation_module: 'static libphp.a sanity check'
);
}
}
@@ -155,14 +171,20 @@ abstract class UnixBuilderBase extends BuilderBase
logger()->info('running frankenphp sanity check');
$frankenphp = BUILD_BIN_PATH . '/frankenphp';
if (!file_exists($frankenphp)) {
throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp);
throw new ValidationException(
"FrankenPHP binary not found: {$frankenphp}",
validation_module: 'FrankenPHP sanity check'
);
}
$prefix = PHP_OS_FAMILY === 'Darwin' ? 'DYLD_' : 'LD_';
[$ret, $output] = shell()
->setEnv(["{$prefix}LIBRARY_PATH" => BUILD_LIB_PATH])
->execWithResult("{$frankenphp} version");
if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) {
throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']');
throw new ValidationException(
'FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']',
validation_module: 'FrankenPHP sanity check'
);
}
}
}
@@ -178,7 +200,7 @@ abstract class UnixBuilderBase extends BuilderBase
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
default => throw new RuntimeException('Deployment does not accept type ' . $type),
default => throw new SPCInternalException("Deployment does not accept type {$type}"),
};
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_BIN_PATH);
@@ -191,7 +213,7 @@ abstract class UnixBuilderBase extends BuilderBase
*/
protected function cleanMake(): void
{
logger()->info('cleaning up');
logger()->info('cleaning up php-src build files');
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\BuildFailureException;
trait fastlz
{
protected function build(): void
@@ -13,10 +15,10 @@ trait fastlz
->exec((getenv('AR') ?: 'ar') . ' rcs libfastlz.a fastlz.o');
if (!copy($this->source_dir . '/fastlz.h', BUILD_INCLUDE_PATH . '/fastlz.h')) {
throw new \RuntimeException('Failed to copy fastlz.h');
throw new BuildFailureException('Failed to copy fastlz.h, file does not exist');
}
if (!copy($this->source_dir . '/libfastlz.a', BUILD_LIB_PATH . '/libfastlz.a')) {
throw new \RuntimeException('Failed to copy libfastlz.a');
throw new BuildFailureException('Failed to copy libfastlz.a, file does not exist');
}
}
}

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\exception\BuildFailureException;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\SPCTarget;
@@ -60,7 +60,7 @@ trait postgresql
$envs .= " LIBS=\"{$libs}{$libcpp}\" ";
}
if ($error_exec_cnt > 0) {
throw new RuntimeException('Failed to get pkg-config information!');
throw new BuildFailureException('Failed to get pkg-config information!');
}
FileSystem::resetDir($this->source_dir . '/build');
@@ -74,7 +74,7 @@ trait postgresql
->exec('sed -i.backup "278 s/^/# /" ../src/Makefile.shlib')
->exec('sed -i.backup "402 s/^/# /" ../src/Makefile.shlib');
} else {
throw new RuntimeException('Unsupported version for postgresql: ' . $version . ' !');
throw new BuildFailureException('Unsupported version for postgresql: ' . $version . ' !');
}
// configure

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\builder\windows;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
class SystemUtil

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace SPC\builder\windows;
use SPC\builder\BuilderBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\SPCInternalException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
@@ -267,7 +267,7 @@ class WindowsBuilder extends BuilderBase
logger()->info('running cli sanity check');
[$ret, $output] = cmd()->execWithResult(BUILD_ROOT_PATH . '\bin\php.exe -n -r "echo \"hello\";"');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new RuntimeException('cli failed sanity check');
throw new ValidationException('cli failed sanity check', validation_module: 'php-cli function check');
}
foreach ($this->getExts(false) as $ext) {
@@ -290,7 +290,10 @@ class WindowsBuilder extends BuilderBase
foreach ($task['conditions'] as $condition => $closure) {
if (!$closure($ret, $out)) {
$raw_out = trim(implode('', $out));
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
throw new ValidationException(
"failure info: {$condition}, code: {$ret}, output: {$raw_out}",
validation_module: "phpmicro sanity check item [{$task_name}]"
);
}
}
}
@@ -308,7 +311,7 @@ class WindowsBuilder extends BuilderBase
$src = match ($type) {
BUILD_TARGET_CLI => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\php.exe",
BUILD_TARGET_MICRO => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\micro.sfx",
default => throw new RuntimeException('Deployment does not accept type ' . $type),
default => throw new SPCInternalException("Deployment does not accept type {$type}"),
};
// with-upx-pack for cli and micro

View File

@@ -5,24 +5,35 @@ declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\builder\windows\SystemUtil;
use SPC\exception\RuntimeException;
use SPC\exception\BuildFailureException;
use SPC\exception\EnvironmentException;
use SPC\store\FileSystem;
class libsodium extends WindowsLibraryBase
{
public const NAME = 'libsodium';
protected function build()
private string $vs_ver_dir;
public function validate(): void
{
FileSystem::replaceFileStr($this->source_dir . '\src\libsodium\include\sodium\export.h', '#ifdef SODIUM_STATIC', '#if 1');
$vs_ver_dir = match (SystemUtil::findVisualStudio()['version']) {
$this->vs_ver_dir = match ($ver = SystemUtil::findVisualStudio()['version']) {
'vs17' => '\vs2022',
'vs16' => '\vs2019',
default => throw new RuntimeException('Current VS version is not supported yet!'),
default => throw new EnvironmentException("Current VS version {$ver} is not supported yet!"),
};
}
public function patchBeforeBuild(): bool
{
FileSystem::replaceFileStr($this->source_dir . '\src\libsodium\include\sodium\export.h', '#ifdef SODIUM_STATIC', '#if 1');
return true;
}
protected function build(): void
{
// start build
cmd()->cd($this->source_dir . '\builds\msvc\\' . $vs_ver_dir)
cmd()->cd($this->source_dir . '\builds\msvc' . $this->vs_ver_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('msbuild'),
'libsodium.sln /t:Rebuild /p:Configuration=StaticRelease /p:Platform=x64 /p:PreprocessorDefinitions="SODIUM_STATIC=1"'
@@ -46,7 +57,7 @@ class libsodium extends WindowsLibraryBase
}
}
if (!$find) {
throw new RuntimeException('libsodium.lib not found');
throw new BuildFailureException("Build libsodium success, but cannot find libsodium.lib in {$this->source_dir}\\bin .");
}
}
}

View File

@@ -5,23 +5,33 @@ declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\builder\windows\SystemUtil;
use SPC\exception\RuntimeException;
use SPC\exception\EnvironmentException;
use SPC\store\FileSystem;
class openssl extends WindowsLibraryBase
{
public const NAME = 'openssl';
private ?string $perl;
public function validate(): void
{
global $argv;
$perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe';
$this->perl = file_exists($perl_path_native) ? ($perl_path_native) : SystemUtil::findCommand('perl.exe');
if ($this->perl === null) {
throw new EnvironmentException(
'You need to install perl first!',
"Please run \"{$argv[0]} doctor\" to fix the environment.",
);
}
}
protected function build(): void
{
$perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe';
$perl = file_exists($perl_path_native) ? ($perl_path_native) : SystemUtil::findCommand('perl.exe');
if ($perl === null) {
throw new RuntimeException('You need to install perl first! (easiest way is using static-php-cli command "doctor")');
}
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper($perl),
$this->builder->makeSimpleWrapper($this->perl),
'Configure zlib VC-WIN64A ' .
'no-shared ' .
'--prefix=' . quote(BUILD_ROOT_PATH) . ' ' .