diff --git a/src/SPC/exception/BuildFailureException.php b/src/SPC/exception/BuildFailureException.php new file mode 100644 index 00000000..f2509e61 --- /dev/null +++ b/src/SPC/exception/BuildFailureException.php @@ -0,0 +1,13 @@ +solution; + } +} diff --git a/src/SPC/exception/ExecutionException.php b/src/SPC/exception/ExecutionException.php new file mode 100644 index 00000000..6a4d1b9d --- /dev/null +++ b/src/SPC/exception/ExecutionException.php @@ -0,0 +1,58 @@ +cmd instanceof UnixShell || $this->cmd instanceof WindowsCmd) { + return $this->cmd->getLastCommand(); + } + return $this->cmd; + } + + /** + * Returns the directory in which the command was executed. + */ + public function getCd(): ?string + { + return $this->cd; + } + + /** + * Returns the environment variables that were set during the command execution. + */ + public function getEnv(): array + { + return $this->env; + } +} diff --git a/src/SPC/exception/FileSystemException.php b/src/SPC/exception/FileSystemException.php index d27e22af..2fa3e916 100644 --- a/src/SPC/exception/FileSystemException.php +++ b/src/SPC/exception/FileSystemException.php @@ -4,4 +4,4 @@ declare(strict_types=1); namespace SPC\exception; -class FileSystemException extends \Exception {} +class FileSystemException extends SPCException {} diff --git a/src/SPC/exception/InterruptException.php b/src/SPC/exception/InterruptException.php index b004f47f..468403d7 100644 --- a/src/SPC/exception/InterruptException.php +++ b/src/SPC/exception/InterruptException.php @@ -4,4 +4,7 @@ declare(strict_types=1); namespace SPC\exception; -class InterruptException extends \Exception {} +/** + * Exception caused by manual intervention. + */ +class InterruptException extends SPCException {} diff --git a/src/SPC/exception/InvalidArgumentException.php b/src/SPC/exception/InvalidArgumentException.php deleted file mode 100644 index 16db5524..00000000 --- a/src/SPC/exception/InvalidArgumentException.php +++ /dev/null @@ -1,7 +0,0 @@ -patch_module; + } +} diff --git a/src/SPC/exception/RuntimeException.php b/src/SPC/exception/RuntimeException.php deleted file mode 100644 index 2d96acb9..00000000 --- a/src/SPC/exception/RuntimeException.php +++ /dev/null @@ -1,7 +0,0 @@ -loadStackTraceInfo(); + } + + public static function bindBuildPHPExtraInfo(array $indent_texts): void + { + self::$build_php_extra_info = $indent_texts; + } + + public function bindExtensionInfo(array $extension_info): void + { + $this->extension_info = $extension_info; + } + + public function addExtraLogFile(string $key, string $filename): void + { + $this->extra_log_files[$key] = $filename; + } + + public function getBuildPHPExtraInfo(): ?array + { + return self::$build_php_extra_info; + } + + /** + * Returns an array containing information about the SPC module. + * + * This method can be overridden by subclasses to provide specific module information. + * + * @return null|array{ + * library_name: string, + * library_class: string, + * os: string, + * file: null|string, + * line: null|int, + * } an array containing module information + */ + public function getLibraryInfo(): ?array + { + return $this->library_info; + } + + /** + * Returns an array containing information about the PHP build process. + * + * @return null|array{ + * builder_class: string, + * os: string, + * file: null|string, + * line: null|int, + * } an array containing PHP build information + */ + public function getBuildPHPInfo(): ?array + { + return $this->build_php_info; + } + + /** + * Returns an array containing information about the SPC extension. + * + * This method can be overridden by subclasses to provide specific extension information. + * + * @return null|array{ + * extension_name: string, + * extension_class: string, + * file: null|string, + * line: null|int, + * } an array containing extension information + */ + public function getExtensionInfo(): ?array + { + return $this->extension_info; + } + + public function getExtraLogFiles(): array + { + return $this->extra_log_files; + } + + private function loadStackTraceInfo(): void + { + $trace = $this->getTrace(); + foreach ($trace as $frame) { + if (!isset($frame['class'])) { + continue; + } + + // Check if the class is a subclass of LibraryBase + if (!$this->library_info && is_subclass_of($frame['class'], LibraryBase::class)) { + try { + $reflection = new \ReflectionClass($frame['class']); + if ($reflection->hasConstant('NAME')) { + $name = $reflection->getConstant('NAME'); + if ($name !== 'unknown') { + $this->library_info = [ + 'library_name' => $name, + 'library_class' => $frame['class'], + 'os' => match (true) { + is_a($frame['class'], BSDLibraryBase::class, true) => 'BSD', + is_a($frame['class'], LinuxLibraryBase::class, true) => 'Linux', + is_a($frame['class'], MacOSLibraryBase::class, true) => 'macOS', + is_a($frame['class'], WindowsLibraryBase::class, true) => 'Windows', + default => 'Unknown', + }, + 'file' => $frame['file'] ?? null, + 'line' => $frame['line'] ?? null, + ]; + continue; + } + } + } catch (\ReflectionException) { + continue; + } + } + + // Check if the class is a subclass of BuilderBase and the method is buildPHP + if (!$this->build_php_info && is_subclass_of($frame['class'], BuilderBase::class) && $frame['function'] === 'buildPHP') { + $reflection = new \ReflectionClass($frame['class']); + if ($reflection->hasProperty('options')) { + $options = $reflection->getProperty('options')->getValue(); + } + $this->build_php_info = [ + 'builder_class' => $frame['class'], + 'builder_options' => $options ?? [], + 'os' => match (true) { + is_a($frame['class'], BSDBuilder::class, true) => 'BSD', + is_a($frame['class'], LinuxBuilder::class, true) => 'Linux', + is_a($frame['class'], MacOSBuilder::class, true) => 'macOS', + is_a($frame['class'], WindowsBuilder::class, true) => 'Windows', + default => 'Unknown', + }, + 'file' => $frame['file'] ?? null, + 'line' => $frame['line'] ?? null, + ]; + } + } + } +} diff --git a/src/SPC/exception/SPCInternalException.php b/src/SPC/exception/SPCInternalException.php new file mode 100644 index 00000000..f0d75d4a --- /dev/null +++ b/src/SPC/exception/SPCInternalException.php @@ -0,0 +1,12 @@ +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" + $this->validation_module = [ + 'class' => $trace['class'] ?? null, + 'function' => $trace['function'], + ]; + break; + } + } else { + $this->validation_module = $validation_module; + } + } + + /** + * Returns the validation module string. + */ + public function getValidationModuleString(): string + { + if ($this->validation_module === null) { + return 'Unknown'; + } + if (is_string($this->validation_module)) { + return $this->validation_module; + } + $str = $this->validation_module['class'] ?? null; + if ($str !== null) { + $str .= '::'; + } + return ($str ?? '') . $this->validation_module['function']; + } +} diff --git a/src/SPC/exception/WrongUsageException.php b/src/SPC/exception/WrongUsageException.php index fa23c1f8..77c93aff 100644 --- a/src/SPC/exception/WrongUsageException.php +++ b/src/SPC/exception/WrongUsageException.php @@ -4,4 +4,10 @@ declare(strict_types=1); namespace SPC\exception; -class WrongUsageException extends \Exception {} +/** + * Exception thrown for incorrect usage of SPC. + * + * This exception is used to indicate that the SPC is being used incorrectly. + * Such as when a command is not supported or an invalid argument is provided. + */ +class WrongUsageException extends SPCException {}