mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-19 13:24:51 +08:00
Enhancement for bin/spc dev:info command
This commit is contained in:
parent
247a254af4
commit
b90356bc1d
@ -203,6 +203,17 @@ class ArtifactCache
|
||||
return $this->cache[$artifact_name]['binary'][$platform] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all binary cache entries for an artifact, keyed by platform string.
|
||||
*
|
||||
* @param string $artifact_name Artifact name
|
||||
* @return array<string, array> Map of platform → cache info (may be empty)
|
||||
*/
|
||||
public function getAllBinaryInfo(string $artifact_name): array
|
||||
{
|
||||
return $this->cache[$artifact_name]['binary'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full path to the cached file/directory.
|
||||
*
|
||||
|
||||
@ -4,10 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command\Dev;
|
||||
|
||||
use StaticPHP\Artifact\ArtifactCache;
|
||||
use StaticPHP\Command\BaseCommand;
|
||||
use StaticPHP\Config\ArtifactConfig;
|
||||
use StaticPHP\Config\PackageConfig;
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Registry\PackageLoader;
|
||||
use StaticPHP\Registry\Registry;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@ -34,18 +38,26 @@ class PackageInfoCommand extends BaseCommand
|
||||
}
|
||||
|
||||
$pkgConfig = PackageConfig::get($packageName);
|
||||
$artifactConfig = ArtifactConfig::get($packageName);
|
||||
// Resolve the actual artifact name:
|
||||
// - string field → named reference (e.g. php → php-src)
|
||||
// - array field → inline artifact, key is package name
|
||||
// - null → no artifact, or may match by package name
|
||||
$artifactField = $pkgConfig['artifact'] ?? null;
|
||||
$artifactName = is_string($artifactField) ? $artifactField : $packageName;
|
||||
$artifactConfig = ArtifactConfig::get($artifactName);
|
||||
$pkgInfo = Registry::getPackageConfigInfo($packageName);
|
||||
$artifactInfo = Registry::getArtifactConfigInfo($packageName);
|
||||
$artifactInfo = Registry::getArtifactConfigInfo($artifactName);
|
||||
$annotationInfo = PackageLoader::getPackageAnnotationInfo($packageName);
|
||||
$cacheInfo = $this->resolveCacheInfo($artifactName, $artifactConfig);
|
||||
|
||||
if ($this->getOption('json')) {
|
||||
return $this->outputJson($packageName, $pkgConfig, $artifactConfig, $pkgInfo, $artifactInfo);
|
||||
return $this->outputJson($packageName, $artifactName, $pkgConfig, $artifactConfig, $pkgInfo, $artifactInfo, $annotationInfo, $cacheInfo);
|
||||
}
|
||||
|
||||
return $this->outputTerminal($packageName, $pkgConfig, $artifactConfig, $pkgInfo, $artifactInfo);
|
||||
return $this->outputTerminal($packageName, $pkgConfig, $artifactConfig, $pkgInfo, $artifactInfo, $annotationInfo, $cacheInfo);
|
||||
}
|
||||
|
||||
private function outputJson(string $name, array $pkgConfig, ?array $artifactConfig, ?array $pkgInfo, ?array $artifactInfo): int
|
||||
private function outputJson(string $name, string $artifactName, array $pkgConfig, ?array $artifactConfig, ?array $pkgInfo, ?array $artifactInfo, ?array $annotationInfo, ?array $cacheInfo): int
|
||||
{
|
||||
$data = [
|
||||
'name' => $name,
|
||||
@ -55,15 +67,24 @@ class PackageInfoCommand extends BaseCommand
|
||||
];
|
||||
|
||||
if ($artifactConfig !== null) {
|
||||
$data['artifact_name'] = $artifactName !== $name ? $artifactName : null;
|
||||
$data['artifact_config_file'] = $artifactInfo ? $this->toRelativePath($artifactInfo['config']) : null;
|
||||
$data['artifact'] = $this->splitArtifactConfig($artifactConfig);
|
||||
}
|
||||
|
||||
if ($annotationInfo !== null) {
|
||||
$data['annotations'] = $annotationInfo;
|
||||
}
|
||||
|
||||
if ($cacheInfo !== null) {
|
||||
$data['cache'] = $cacheInfo;
|
||||
}
|
||||
|
||||
$this->output->writeln(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function outputTerminal(string $name, array $pkgConfig, ?array $artifactConfig, ?array $pkgInfo, ?array $artifactInfo): int
|
||||
private function outputTerminal(string $name, array $pkgConfig, ?array $artifactConfig, ?array $pkgInfo, ?array $artifactInfo, ?array $annotationInfo, ?array $cacheInfo): int
|
||||
{
|
||||
$type = $pkgConfig['type'] ?? 'unknown';
|
||||
$registry = $pkgInfo['registry'] ?? 'unknown';
|
||||
@ -86,12 +107,15 @@ class PackageInfoCommand extends BaseCommand
|
||||
// Artifact config
|
||||
if ($artifactConfig !== null) {
|
||||
$artifactFile = $artifactInfo ? $this->toRelativePath($artifactInfo['config']) : 'unknown';
|
||||
$this->output->writeln("<comment>── Artifact Config ──</comment> <info>file:</info> {$artifactFile}");
|
||||
|
||||
// Check if artifact config is inline (embedded in pkg config) or separate
|
||||
$inlineArtifact = $pkgConfig['artifact'] ?? null;
|
||||
if (is_array($inlineArtifact)) {
|
||||
$artifactField = $pkgConfig['artifact'] ?? null;
|
||||
if (is_string($artifactField)) {
|
||||
// Named reference: show the artifact name it points to
|
||||
$this->output->writeln("<comment>── Artifact Config ──</comment> <info>artifact:</info> <fg=cyan>{$artifactField}</> <info>file:</info> {$artifactFile}");
|
||||
} elseif (is_array($artifactField)) {
|
||||
$this->output->writeln("<comment>── Artifact Config ──</comment> <info>file:</info> {$artifactFile}");
|
||||
$this->output->writeln('<info> (inline in package config)</info>');
|
||||
} else {
|
||||
$this->output->writeln("<comment>── Artifact Config ──</comment> <info>file:</info> {$artifactFile}");
|
||||
}
|
||||
|
||||
$split = $this->splitArtifactConfig($artifactConfig);
|
||||
@ -107,9 +131,122 @@ class PackageInfoCommand extends BaseCommand
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
// Annotation section
|
||||
$this->outputAnnotationSection($name, $annotationInfo);
|
||||
|
||||
// Cache status section
|
||||
$this->outputCacheSection($cacheInfo);
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function outputAnnotationSection(string $packageName, ?array $annotationInfo): void
|
||||
{
|
||||
if ($annotationInfo === null) {
|
||||
$this->output->writeln('<comment>── Annotations ──</comment> <fg=gray>(no annotation class registered)</>');
|
||||
$this->output->writeln('');
|
||||
return;
|
||||
}
|
||||
|
||||
$shortClass = $this->classBaseName($annotationInfo['class']);
|
||||
$this->output->writeln("<comment>── Annotations ──</comment> <info>class:</info> <fg=cyan>{$shortClass}</>");
|
||||
$this->output->writeln(" <fg=gray>{$annotationInfo['class']}</>");
|
||||
|
||||
// Method-level hooks
|
||||
$methods = $annotationInfo['methods'];
|
||||
if (!empty($methods)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>Method hooks:</info>');
|
||||
foreach ($methods as $methodName => $attrs) {
|
||||
$attrList = implode(' ', array_map(fn ($a) => $this->formatAttr($a), $attrs));
|
||||
$this->output->writeln(" <fg=cyan>{$methodName}()</> {$attrList}");
|
||||
}
|
||||
}
|
||||
|
||||
// Before-stage hooks targeting this package (inbound)
|
||||
$beforeStages = $annotationInfo['before_stages'];
|
||||
if (!empty($beforeStages)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>Before-stage hooks (inbound):</info>');
|
||||
foreach ($beforeStages as $stage => $hooks) {
|
||||
foreach ($hooks as $hook) {
|
||||
$source = $this->classBaseName($hook['class']) . '::' . $hook['method'] . '()';
|
||||
$cond = $hook['only_when'] !== null ? " <fg=gray>(only_when: {$hook['only_when']})</>" : '';
|
||||
$this->output->writeln(" <fg=yellow>{$stage}</> ← {$source}{$cond}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After-stage hooks targeting this package (inbound)
|
||||
$afterStages = $annotationInfo['after_stages'];
|
||||
if (!empty($afterStages)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>After-stage hooks (inbound):</info>');
|
||||
foreach ($afterStages as $stage => $hooks) {
|
||||
foreach ($hooks as $hook) {
|
||||
$source = $this->classBaseName($hook['class']) . '::' . $hook['method'] . '()';
|
||||
$cond = $hook['only_when'] !== null ? " <fg=gray>(only_when: {$hook['only_when']})</>" : '';
|
||||
$this->output->writeln(" <fg=yellow>{$stage}</> ← {$source}{$cond}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Outbound hooks: stages this package's class registers on other packages (exclude self-hooks)
|
||||
$outboundBefore = $annotationInfo['outbound_before_stages'] ?? [];
|
||||
$outboundAfter = $annotationInfo['outbound_after_stages'] ?? [];
|
||||
// Filter out entries targeting the same package — those are already shown inbound
|
||||
$outboundBefore = array_filter($outboundBefore, fn ($pkg) => $pkg !== $packageName, ARRAY_FILTER_USE_KEY);
|
||||
$outboundAfter = array_filter($outboundAfter, fn ($pkg) => $pkg !== $packageName, ARRAY_FILTER_USE_KEY);
|
||||
if (!empty($outboundBefore) || !empty($outboundAfter)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>Hooks on other packages (outbound):</info>');
|
||||
foreach ($outboundBefore as $targetPkg => $stages) {
|
||||
foreach ($stages as $stage => $hooks) {
|
||||
foreach ($hooks as $hook) {
|
||||
$cond = $hook['only_when'] !== null ? " <fg=gray>(only_when: {$hook['only_when']})</>" : '';
|
||||
$this->output->writeln(" <fg=magenta>#[BeforeStage]</> → <fg=cyan>{$targetPkg}</> <fg=yellow>{$stage}</> {$hook['method']}(){$cond}");
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($outboundAfter as $targetPkg => $stages) {
|
||||
foreach ($stages as $stage => $hooks) {
|
||||
foreach ($hooks as $hook) {
|
||||
$cond = $hook['only_when'] !== null ? " <fg=gray>(only_when: {$hook['only_when']})</>" : '';
|
||||
$this->output->writeln(" <fg=magenta>#[AfterStage]</> → <fg=cyan>{$targetPkg}</> <fg=yellow>{$stage}</> {$hook['method']}(){$cond}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a single attribute entry (from annotation_map) as a colored inline string.
|
||||
*
|
||||
* @param array{attr: string, args: array<string, mixed>} $attr
|
||||
*/
|
||||
private function formatAttr(array $attr): string
|
||||
{
|
||||
$name = $attr['attr'];
|
||||
$args = $attr['args'];
|
||||
if (empty($args)) {
|
||||
return "<fg=magenta>#[{$name}]</>";
|
||||
}
|
||||
$argStr = implode(', ', array_map(
|
||||
fn ($v) => is_string($v) ? "'{$v}'" : (string) $v,
|
||||
array_values($args)
|
||||
));
|
||||
return "<fg=magenta>#[{$name}({$argStr})]</>";
|
||||
}
|
||||
|
||||
/** Return the trailing class name component without the namespace. */
|
||||
private function classBaseName(string $fqcn): string
|
||||
{
|
||||
$parts = explode('\\', $fqcn);
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split artifact config into logical sections for cleaner display.
|
||||
*
|
||||
@ -190,4 +327,91 @@ class PackageInfoCommand extends BaseCommand
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build cache status data for display/JSON.
|
||||
* Returns null when there is no artifact config for this package.
|
||||
*/
|
||||
private function resolveCacheInfo(string $name, ?array $artifactConfig): ?array
|
||||
{
|
||||
if ($artifactConfig === null) {
|
||||
return null;
|
||||
}
|
||||
$cache = ApplicationContext::get(ArtifactCache::class);
|
||||
$currentPlatform = SystemTarget::getCurrentPlatformString();
|
||||
$hasSource = array_key_exists('source', $artifactConfig) || array_key_exists('source-mirror', $artifactConfig);
|
||||
$hasBinary = array_key_exists('binary', $artifactConfig) || array_key_exists('binary-mirror', $artifactConfig);
|
||||
return [
|
||||
'current_platform' => $currentPlatform,
|
||||
'has_source' => $hasSource,
|
||||
'has_binary' => $hasBinary,
|
||||
'source' => $hasSource ? [
|
||||
'downloaded' => $cache->isSourceDownloaded($name),
|
||||
'info' => $cache->getSourceInfo($name),
|
||||
] : null,
|
||||
'binary' => $hasBinary ? $cache->getAllBinaryInfo($name) : null,
|
||||
];
|
||||
}
|
||||
|
||||
private function outputCacheSection(?array $cacheInfo): void
|
||||
{
|
||||
if ($cacheInfo === null) {
|
||||
$this->output->writeln('<comment>── Cache Status ──</comment> <fg=gray>(no artifact config)</>');
|
||||
$this->output->writeln('');
|
||||
return;
|
||||
}
|
||||
|
||||
$platform = $cacheInfo['current_platform'];
|
||||
$this->output->writeln("<comment>── Cache Status ──</comment> <fg=gray>current platform: {$platform}</>");
|
||||
|
||||
// Source
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>source:</info>');
|
||||
if (!$cacheInfo['has_source']) {
|
||||
$this->output->writeln(' <fg=gray>─ not applicable</>');
|
||||
} elseif ($cacheInfo['source']['downloaded'] && $cacheInfo['source']['info'] !== null) {
|
||||
$this->output->writeln(' <fg=green>✓ downloaded</> ' . $this->formatCacheEntry($cacheInfo['source']['info']));
|
||||
} else {
|
||||
$this->output->writeln(' <fg=yellow>✗ not downloaded</>');
|
||||
}
|
||||
|
||||
// Binary
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' <info>binary:</info>');
|
||||
if (!$cacheInfo['has_binary']) {
|
||||
$this->output->writeln(' <fg=gray>─ not applicable</>');
|
||||
} elseif (empty($cacheInfo['binary'])) {
|
||||
$this->output->writeln(" <fg=yellow>✗ {$platform}</> <fg=gray>(current — not cached)</>");
|
||||
} else {
|
||||
$allBinary = $cacheInfo['binary'];
|
||||
foreach ($allBinary as $binPlatform => $binInfo) {
|
||||
$isCurrent = $binPlatform === $platform;
|
||||
$tag = $isCurrent ? ' <fg=gray>(current)</>' : '';
|
||||
if ($binInfo !== null) {
|
||||
$this->output->writeln(" <fg=green>✓ {$binPlatform}</>{$tag} " . $this->formatCacheEntry($binInfo));
|
||||
} else {
|
||||
$this->output->writeln(" <fg=red>✗ {$binPlatform}</>{$tag}");
|
||||
}
|
||||
}
|
||||
// Show current platform if not already listed
|
||||
if (!array_key_exists($platform, $allBinary)) {
|
||||
$this->output->writeln(" <fg=yellow>✗ {$platform}</> <fg=gray>(current — not cached)</>");
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
private function formatCacheEntry(array $info): string
|
||||
{
|
||||
$type = $info['cache_type'] ?? '?';
|
||||
$version = $info['version'] !== null ? " {$info['version']}" : '';
|
||||
$time = isset($info['time']) ? ' ' . date('Y-m-d H:i', (int) $info['time']) : '';
|
||||
$file = match ($type) {
|
||||
'archive', 'file' => isset($info['filename']) ? " <fg=gray>{$info['filename']}</>" : '',
|
||||
'git', 'local' => isset($info['dirname']) ? " <fg=gray>{$info['dirname']}</>" : '',
|
||||
default => '',
|
||||
};
|
||||
return "<fg=cyan>[{$type}]</>{$version}{$time}{$file}";
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,42 @@ class PackageLoader
|
||||
/** @var array<string, true> Track loaded classes to prevent duplicates */
|
||||
private static array $loaded_classes = [];
|
||||
|
||||
/**
|
||||
* Annotation metadata keyed by package name, capturing the defining class and its method-level attributes.
|
||||
*
|
||||
* @var array<string, array{class: string, methods: array<string, list<array{attr: string, args: array<string, mixed>}>>}>
|
||||
*/
|
||||
private static array $annotation_map = [];
|
||||
|
||||
/**
|
||||
* Source metadata for #[BeforeStage] hooks, keyed by target package name → stage name.
|
||||
*
|
||||
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string}>>>
|
||||
*/
|
||||
private static array $before_stage_meta = [];
|
||||
|
||||
/**
|
||||
* Source metadata for #[AfterStage] hooks, keyed by target package name → stage name.
|
||||
*
|
||||
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string}>>>
|
||||
*/
|
||||
private static array $after_stage_meta = [];
|
||||
|
||||
/**
|
||||
* Reverse index of #[BeforeStage] hooks, keyed by registering class → target package → stage.
|
||||
* Enables O(1) "outbound hook" lookup: what stages does a given class hook into on other packages?
|
||||
*
|
||||
* @var array<string, array<string, array<string, list<array{method: string, only_when: ?string}>>>>
|
||||
*/
|
||||
private static array $class_before_stage_meta = [];
|
||||
|
||||
/**
|
||||
* Reverse index of #[AfterStage] hooks, keyed by registering class → target package → stage.
|
||||
*
|
||||
* @var array<string, array<string, array<string, list<array{method: string, only_when: ?string}>>>>
|
||||
*/
|
||||
private static array $class_after_stage_meta = [];
|
||||
|
||||
public static function initPackageInstances(): void
|
||||
{
|
||||
if (self::$packages !== null) {
|
||||
@ -213,8 +249,19 @@ class PackageLoader
|
||||
Validate::class => $pkg->setValidateCallback([$instance_class, $method->getName()]),
|
||||
default => null,
|
||||
};
|
||||
|
||||
// Capture annotation metadata for inspection (dev:info, future event-trace commands)
|
||||
$meta_attr = self::annotationShortName($method_attribute->getName());
|
||||
if ($meta_attr !== null) {
|
||||
self::$annotation_map[$pkg->getName()]['methods'][$method->getName()][] = [
|
||||
'attr' => $meta_attr,
|
||||
'args' => self::annotationArgs($method_instance),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Record which class defines this package (set once; IS_REPEATABLE may loop more than once)
|
||||
self::$annotation_map[$pkg->getName()]['class'] ??= $class_name;
|
||||
// register package
|
||||
self::$packages[$pkg->getName()] = $pkg;
|
||||
}
|
||||
@ -260,6 +307,63 @@ class PackageLoader
|
||||
return self::$after_stages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get annotation metadata for a specific package.
|
||||
*
|
||||
* Returns null if no annotation class was loaded for this package (config-only package).
|
||||
* The returned structure includes the defining class name, per-method attribute list,
|
||||
* inbound BeforeStage/AfterStage hooks targeting this package, and outbound hooks that
|
||||
* this package's class registers on other packages.
|
||||
*
|
||||
* @return null|array{
|
||||
* class: string,
|
||||
* methods: array<string, list<array{attr: string, args: array<string, mixed>}>>,
|
||||
* before_stages: array<string, list<array{class: string, method: string, only_when: ?string}>>,
|
||||
* after_stages: array<string, list<array{class: string, method: string, only_when: ?string}>>,
|
||||
* outbound_before_stages: array<string, array<string, list<array{method: string, only_when: ?string}>>>,
|
||||
* outbound_after_stages: array<string, array<string, list<array{method: string, only_when: ?string}>>>
|
||||
* }
|
||||
*/
|
||||
public static function getPackageAnnotationInfo(string $name): ?array
|
||||
{
|
||||
$class_info = self::$annotation_map[$name] ?? null;
|
||||
if ($class_info === null) {
|
||||
return null;
|
||||
}
|
||||
$class = $class_info['class'];
|
||||
return [
|
||||
'class' => $class,
|
||||
'methods' => $class_info['methods'],
|
||||
'before_stages' => self::$before_stage_meta[$name] ?? [],
|
||||
'after_stages' => self::$after_stage_meta[$name] ?? [],
|
||||
'outbound_before_stages' => self::$class_before_stage_meta[$class] ?? [],
|
||||
'outbound_after_stages' => self::$class_after_stage_meta[$class] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all annotation metadata keyed by package name.
|
||||
* Useful for future event-trace commands or cross-package inspection.
|
||||
*
|
||||
* @return array<string, array{class: string, methods: array, before_stages: array, after_stages: array, outbound_before_stages: array, outbound_after_stages: array}>
|
||||
*/
|
||||
public static function getAllAnnotations(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (self::$annotation_map as $name => $info) {
|
||||
$class = $info['class'];
|
||||
$result[$name] = [
|
||||
'class' => $class,
|
||||
'methods' => $info['methods'],
|
||||
'before_stages' => self::$before_stage_meta[$name] ?? [],
|
||||
'after_stages' => self::$after_stage_meta[$name] ?? [],
|
||||
'outbound_before_stages' => self::$class_before_stage_meta[$class] ?? [],
|
||||
'outbound_after_stages' => self::$class_after_stage_meta[$class] ?? [],
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getBeforeStageCallbacks(string $package_name, string $stage): iterable
|
||||
{
|
||||
// match condition
|
||||
@ -385,6 +489,16 @@ class PackageLoader
|
||||
}
|
||||
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
||||
self::$before_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved];
|
||||
$registering_class = get_class($instance_class);
|
||||
self::$before_stage_meta[$package_name][$stage][] = [
|
||||
'class' => $registering_class,
|
||||
'method' => $method->getName(),
|
||||
'only_when' => $method_instance->only_when_package_resolved,
|
||||
];
|
||||
self::$class_before_stage_meta[$registering_class][$package_name][$stage][] = [
|
||||
'method' => $method->getName(),
|
||||
'only_when' => $method_instance->only_when_package_resolved,
|
||||
];
|
||||
}
|
||||
|
||||
private static function addAfterStage(\ReflectionMethod $method, ?Package $pkg, mixed $instance_class, object $method_instance): void
|
||||
@ -400,5 +514,49 @@ class PackageLoader
|
||||
}
|
||||
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
||||
self::$after_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved];
|
||||
$registering_class = get_class($instance_class);
|
||||
self::$after_stage_meta[$package_name][$stage][] = [
|
||||
'class' => $registering_class,
|
||||
'method' => $method->getName(),
|
||||
'only_when' => $method_instance->only_when_package_resolved,
|
||||
];
|
||||
self::$class_after_stage_meta[$registering_class][$package_name][$stage][] = [
|
||||
'method' => $method->getName(),
|
||||
'only_when' => $method_instance->only_when_package_resolved,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a fully-qualified attribute class name to a short display name for metadata storage.
|
||||
* Returns null for attributes that are not tracked in the annotation map.
|
||||
*/
|
||||
private static function annotationShortName(string $attr): ?string
|
||||
{
|
||||
return match ($attr) {
|
||||
Stage::class => 'Stage',
|
||||
BuildFor::class => 'BuildFor',
|
||||
PatchBeforeBuild::class => 'PatchBeforeBuild',
|
||||
CustomPhpConfigureArg::class => 'CustomPhpConfigureArg',
|
||||
InitPackage::class => 'InitPackage',
|
||||
ResolveBuild::class => 'ResolveBuild',
|
||||
Info::class => 'Info',
|
||||
Validate::class => 'Validate',
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the meaningful constructor arguments from an attribute instance as a key-value array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private static function annotationArgs(object $inst): array
|
||||
{
|
||||
return match (true) {
|
||||
$inst instanceof Stage => array_filter(['function' => $inst->function], fn ($v) => $v !== null),
|
||||
$inst instanceof BuildFor => ['os' => $inst->os],
|
||||
$inst instanceof CustomPhpConfigureArg => array_filter(['os' => $inst->os], fn ($v) => $v !== ''),
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user