mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-17 05:45:35 +08:00
157 lines
5.0 KiB
PHP
157 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace StaticPHP\Command\Dev;
|
|
|
|
use StaticPHP\Command\BaseCommand;
|
|
use StaticPHP\Registry\Registry;
|
|
use Symfony\Component\Console\Attribute\AsCommand;
|
|
use Symfony\Component\Console\Input\InputOption;
|
|
use Symfony\Component\Yaml\Yaml;
|
|
|
|
#[AsCommand('dev:lint-config', 'Lint configuration file format', ['dev:sort-config'])]
|
|
class LintConfigCommand extends BaseCommand
|
|
{
|
|
protected bool $no_motd = true;
|
|
|
|
public function handle(): int
|
|
{
|
|
$checkOnly = $this->input->getOption('check');
|
|
$hasChanges = false;
|
|
|
|
// get loaded configs
|
|
$loded_configs = Registry::getLoadedArtifactConfigs();
|
|
foreach ($loded_configs as $file) {
|
|
if ($this->sortConfigFile($file, 'artifact', $checkOnly)) {
|
|
$hasChanges = true;
|
|
}
|
|
}
|
|
$loaded_pkg_configs = Registry::getLoadedPackageConfigs();
|
|
foreach ($loaded_pkg_configs as $file) {
|
|
if ($this->sortConfigFile($file, 'package', $checkOnly)) {
|
|
$hasChanges = true;
|
|
}
|
|
}
|
|
|
|
if ($checkOnly && $hasChanges) {
|
|
$this->output->writeln('<error>Some config files need sorting. Run "bin/spc dev:lint-config" to fix them.</error>');
|
|
return static::VALIDATION_ERROR;
|
|
}
|
|
|
|
if (!$hasChanges) {
|
|
$this->output->writeln('<info>No changes.</info>');
|
|
}
|
|
return static::SUCCESS;
|
|
}
|
|
|
|
public function artifactSortKey(string $a, string $b): int
|
|
{
|
|
// sort by predefined order, other not matching keys go to the end alphabetically
|
|
$order = ['source', 'source-mirror', 'binary', 'binary-mirror', 'metadata'];
|
|
|
|
$pos_a = array_search($a, $order, true);
|
|
$pos_b = array_search($b, $order, true);
|
|
|
|
// Both in order list
|
|
if ($pos_a !== false && $pos_b !== false) {
|
|
return $pos_a <=> $pos_b;
|
|
}
|
|
|
|
// Only $a in order list
|
|
if ($pos_a !== false) {
|
|
return -1;
|
|
}
|
|
|
|
// Only $b in order list
|
|
if ($pos_b !== false) {
|
|
return 1;
|
|
}
|
|
|
|
// Neither in order list, sort alphabetically
|
|
return $a <=> $b;
|
|
}
|
|
|
|
public function packageSortKey(string $a, string $b): int
|
|
{
|
|
// sort by predefined order, other not matching keys go to the end alphabetically
|
|
$order = ['type', 'artifact', 'depends', 'suggests', 'frameworks'];
|
|
|
|
// Handle suffix patterns (e.g., 'depends@unix', 'static-libs@windows')
|
|
$base_a = preg_replace('/@(unix|windows|macos|linux|freebsd|bsd)$/', '', $a);
|
|
$base_b = preg_replace('/@(unix|windows|macos|linux|freebsd|bsd)$/', '', $b);
|
|
|
|
$pos_a = array_search($base_a, $order, true);
|
|
$pos_b = array_search($base_b, $order, true);
|
|
|
|
// Both in order list
|
|
if ($pos_a !== false && $pos_b !== false) {
|
|
if ($pos_a === $pos_b) {
|
|
// Same base field, sort by suffix
|
|
return $a <=> $b;
|
|
}
|
|
return $pos_a <=> $pos_b;
|
|
}
|
|
|
|
// Only $a in order list
|
|
if ($pos_a !== false) {
|
|
return -1;
|
|
}
|
|
|
|
// Only $b in order list
|
|
if ($pos_b !== false) {
|
|
return 1;
|
|
}
|
|
|
|
// Neither in order list, sort alphabetically
|
|
return $a <=> $b;
|
|
}
|
|
|
|
protected function configure(): void
|
|
{
|
|
$this->addOption('check', null, InputOption::VALUE_NONE, 'Check if config files need sorting without modifying them');
|
|
}
|
|
|
|
private function sortConfigFile(mixed $file, string $config_type, bool $checkOnly): bool
|
|
{
|
|
// read file content with different extensions
|
|
$content = file_get_contents($file);
|
|
if ($content === false) {
|
|
$this->output->writeln("Failed to read config file: {$file}");
|
|
return false;
|
|
}
|
|
$data = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
|
'json' => json_decode($content, true),
|
|
'yml', 'yaml' => Yaml::parse($content),
|
|
default => null,
|
|
};
|
|
if (!is_array($data)) {
|
|
$this->output->writeln("Invalid format in config file: {$file}");
|
|
return false;
|
|
}
|
|
ksort($data);
|
|
foreach ($data as &$config) {
|
|
uksort($config, $config_type === 'artifact' ? [$this, 'artifactSortKey'] : [$this, 'packageSortKey']);
|
|
}
|
|
unset($config);
|
|
$new_content = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
|
'json' => json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n",
|
|
'yml', 'yaml' => Yaml::dump($data, 4, 2),
|
|
default => null,
|
|
};
|
|
|
|
// Check if content has changed
|
|
if ($content !== $new_content) {
|
|
if ($checkOnly) {
|
|
$this->output->writeln("<comment>File needs sorting: {$file}</comment>");
|
|
return true;
|
|
}
|
|
file_put_contents($file, $new_content);
|
|
$this->output->writeln("Sorted config file: {$file}");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|