mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-19 13:24:51 +08:00
180 lines
5.2 KiB
PHP
180 lines
5.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace StaticPHP\Package;
|
|
|
|
use StaticPHP\Artifact\Artifact;
|
|
use StaticPHP\Artifact\ArtifactLoader;
|
|
use StaticPHP\Config\PackageConfig;
|
|
use StaticPHP\DI\ApplicationContext;
|
|
use StaticPHP\Exception\SPCInternalException;
|
|
|
|
abstract class Package
|
|
{
|
|
use PackageCallbacksTrait;
|
|
|
|
/**
|
|
* @var array<string, callable> $stages Defined stages for the package
|
|
*/
|
|
protected array $stages = [];
|
|
|
|
/** @var array<string, callable> $build_functions Build functions for different OS binding */
|
|
protected array $build_functions = [];
|
|
|
|
/**
|
|
* @param string $name Name of the package
|
|
* @param string $type Type of the package
|
|
*/
|
|
public function __construct(public readonly string $name, public readonly string $type) {}
|
|
|
|
/**
|
|
* Run a defined stage of the package.
|
|
* If the stage is not defined, an exception should be thrown.
|
|
*
|
|
* @param string $name Name of the stage to run
|
|
* @param array $context Additional context to pass to the stage callback
|
|
* @return mixed Based on the stage definition, return the result of the stage
|
|
*/
|
|
public function runStage(string $name, array $context = []): mixed
|
|
{
|
|
if (!isset($this->stages[$name])) {
|
|
throw new SPCInternalException("Stage '{$name}' is not defined for package '{$this->name}'.");
|
|
}
|
|
|
|
// Merge package context with provided context
|
|
/** @noinspection PhpDuplicateArrayKeysInspection */
|
|
$stageContext = array_merge([
|
|
Package::class => $this,
|
|
static::class => $this,
|
|
], $context);
|
|
|
|
// emit BeforeStage
|
|
$this->emitBeforeStage($name, $stageContext);
|
|
|
|
$ret = ApplicationContext::invoke($this->stages[$name], $stageContext);
|
|
// emit AfterStage
|
|
$this->emitAfterStage($name, $stageContext, $ret);
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Add a build function for a specific platform.
|
|
*
|
|
* @param string $os_family PHP_OS_FAMILY
|
|
* @param callable $func Function to build for the platform
|
|
*/
|
|
public function addBuildFunction(string $os_family, callable $func): void
|
|
{
|
|
$this->build_functions[$os_family] = $func;
|
|
if ($os_family === PHP_OS_FAMILY) {
|
|
$this->addStage('build', $func);
|
|
}
|
|
}
|
|
|
|
public function isInstalled(): bool
|
|
{
|
|
// By default, assume package is not installed.
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Add a stage to the package.
|
|
*
|
|
* @param string $name Stage name
|
|
* @param callable $stage Stage callable
|
|
*/
|
|
public function addStage(string $name, callable $stage): void
|
|
{
|
|
$this->stages[$name] = $stage;
|
|
}
|
|
|
|
/**
|
|
* Check if the package has a specific stage defined.
|
|
*
|
|
* @param string $name Stage name
|
|
*/
|
|
public function hasStage(string $name): bool
|
|
{
|
|
return isset($this->stages[$name]);
|
|
}
|
|
|
|
/**
|
|
* Get the name of the package.
|
|
*/
|
|
public function getName(): string
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
/**
|
|
* Get the type of the package.
|
|
*/
|
|
public function getType(): string
|
|
{
|
|
return $this->type;
|
|
}
|
|
|
|
/**
|
|
* Get the artifact associated with the package, or null if none is defined.
|
|
*
|
|
* @return null|Artifact Artifact instance or null
|
|
*/
|
|
public function getArtifact(): ?Artifact
|
|
{
|
|
// find config
|
|
$artifact_name = PackageConfig::get($this->name, 'artifact');
|
|
return $artifact_name !== null ? ArtifactLoader::getArtifactInstance($artifact_name) : null;
|
|
}
|
|
|
|
/**
|
|
* Check if the artifact has source available.
|
|
*/
|
|
public function hasSource(): bool
|
|
{
|
|
return $this->getArtifact()?->hasSource() ?? false;
|
|
}
|
|
|
|
/**
|
|
* Get source directory of the package.
|
|
* If the source artifact is not available, an exception will be thrown.
|
|
*/
|
|
public function getSourceDir(): string
|
|
{
|
|
if (($artifact = $this->getArtifact()) && $artifact->hasSource()) {
|
|
return $artifact->getSourceDir();
|
|
}
|
|
throw new SPCInternalException("Source directory for package {$this->name} is not available because the source artifact is missing.");
|
|
}
|
|
|
|
/**
|
|
* Check if the package has a binary available for current OS and architecture.
|
|
*/
|
|
public function hasLocalBinary(): bool
|
|
{
|
|
return $this->getArtifact()?->hasPlatformBinary() ?? false;
|
|
}
|
|
|
|
/**
|
|
* Get the snake_case name of the package.
|
|
*/
|
|
protected function getSnakeCaseName(): string
|
|
{
|
|
return str_replace('-', '_', $this->name);
|
|
}
|
|
|
|
private function emitBeforeStage(string $stage, array $stageContext): void
|
|
{
|
|
foreach (PackageLoader::getBeforeStageCallbacks($this->getName(), $stage) as $callback) {
|
|
ApplicationContext::invoke($callback, $stageContext);
|
|
}
|
|
}
|
|
|
|
private function emitAfterStage(string $stage, array $stageContext, mixed $return_value): void
|
|
{
|
|
foreach (PackageLoader::getAfterStageCallbacks($this->getName(), $stage) as $callback) {
|
|
ApplicationContext::invoke($callback, array_merge($stageContext, ['return_value' => $return_value]));
|
|
}
|
|
}
|
|
}
|