mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
Add doctor cache check and version management to ensure environment validation
This commit is contained in:
parent
7623b9e673
commit
c218aef947
3
.gitignore
vendored
3
.gitignore
vendored
@ -33,6 +33,9 @@ packlib_files.txt
|
||||
.php-cs-fixer.cache
|
||||
.phpunit.result.cache
|
||||
|
||||
# doctor cache fallback (when ~/.cache/spc/ is not writable)
|
||||
.spc-doctor.lock
|
||||
|
||||
# exclude self-runtime
|
||||
/bin/*
|
||||
!/bin/spc*
|
||||
|
||||
@ -7,6 +7,7 @@ namespace Package\Target;
|
||||
use Package\Target\php\frankenphp;
|
||||
use Package\Target\php\unix;
|
||||
use Package\Target\php\windows;
|
||||
use StaticPHP\Artifact\ArtifactCache;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\Info;
|
||||
use StaticPHP\Attribute\Package\InitPackage;
|
||||
@ -104,6 +105,24 @@ class php extends TargetPackage
|
||||
throw new WrongUsageException('PHP version file format is malformed, please remove "./source/php-src" dir and download/extract again');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP version from source archive filename
|
||||
*
|
||||
* @return null|string PHP version (e.g., "8.4.0")
|
||||
*/
|
||||
public static function getPHPVersionFromArchive(bool $return_null_if_failed = false): ?string
|
||||
{
|
||||
$archives = ApplicationContext::get(ArtifactCache::class)->getSourceInfo('php-src');
|
||||
$filename = $archives['filename'] ?? '';
|
||||
if (!preg_match('/php-(\d+\.\d+\.\d+(?:RC\d+|alpha\d+|beta\d+)?)\.tar\.(?:gz|bz2|xz)/', $filename, $match)) {
|
||||
if ($return_null_if_failed) {
|
||||
return null;
|
||||
}
|
||||
throw new WrongUsageException('PHP source archive filename format is malformed (got: ' . $filename . ')');
|
||||
}
|
||||
return $match[1];
|
||||
}
|
||||
|
||||
#[InitPackage]
|
||||
public function init(TargetPackage $package): void
|
||||
{
|
||||
@ -255,6 +274,7 @@ class php extends TargetPackage
|
||||
'Build Target' => getenv('SPC_TARGET') ?: '',
|
||||
'Build Toolchain' => ToolchainManager::getToolchainClass(),
|
||||
'Build SAPI' => implode(', ', $sapis),
|
||||
'PHP Version' => self::getPHPVersion(return_null_if_failed: true) ?? self::getPHPVersionFromArchive(return_null_if_failed: true) ?? 'Unknown',
|
||||
'Static Extensions (' . count($static_extensions) . ')' => implode(',', array_map(fn ($x) => substr($x->getName(), 4), $static_extensions)),
|
||||
'Shared Extensions (' . count($shared_extensions) . ')' => implode(',', $shared_extensions),
|
||||
'Install Packages (' . count($install_packages) . ')' => implode(',', array_map(fn ($x) => $x->getName(), $install_packages)),
|
||||
|
||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Doctor\Doctor;
|
||||
use StaticPHP\Exception\ExceptionHandler;
|
||||
use StaticPHP\Exception\SPCException;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@ -118,6 +119,21 @@ abstract class BaseCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn the user if doctor has not been run (or is outdated).
|
||||
* Set SPC_SKIP_DOCTOR_CHECK=1 to suppress.
|
||||
*/
|
||||
protected function checkDoctorCache(): void
|
||||
{
|
||||
if (getenv('SPC_SKIP_DOCTOR_CHECK') || Doctor::isHealthy()) {
|
||||
return;
|
||||
}
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>[WARNING] Please run `spc doctor` first to verify your build environment.</comment>');
|
||||
$this->output->writeln('');
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
protected function getOption(string $name): mixed
|
||||
{
|
||||
return $this->input->getOption($name);
|
||||
|
||||
@ -44,6 +44,8 @@ class BuildLibsCommand extends BaseCommand
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->checkDoctorCache();
|
||||
|
||||
$libs = parse_comma_list($this->input->getArgument('libraries'));
|
||||
|
||||
$installer = new PackageInstaller($this->input->getOptions());
|
||||
|
||||
@ -37,6 +37,8 @@ class BuildTargetCommand extends BaseCommand
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->checkDoctorCache();
|
||||
|
||||
// resolve legacy options to new options
|
||||
V2CompatLayer::convertOptions($this->input);
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ class DoctorCommand extends BaseCommand
|
||||
};
|
||||
$doctor = new Doctor($this->output, $fix_policy);
|
||||
if ($doctor->checkAll()) {
|
||||
Doctor::markPassed();
|
||||
$this->output->writeln('<info>Doctor check complete !</info>');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
@ -56,6 +56,8 @@ class DownloadCommand extends BaseCommand
|
||||
return $this->handleClean();
|
||||
}
|
||||
|
||||
$this->checkDoctorCache();
|
||||
|
||||
$downloader = new ArtifactDownloader(DownloaderOptions::extractFromConsoleOptions($this->input->getOptions()));
|
||||
|
||||
// arguments
|
||||
|
||||
@ -9,6 +9,7 @@ use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Exception\SPCException;
|
||||
use StaticPHP\Registry\DoctorLoader;
|
||||
use StaticPHP\Runtime\Shell\Shell;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use StaticPHP\Util\InteractiveTerm;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use ZM\Logger\ConsoleColor;
|
||||
@ -25,6 +26,29 @@ readonly class Doctor
|
||||
logger()->debug("Loaded doctor check items:\n\t" . implode("\n\t", $names));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if doctor was previously passed with the current SPC version.
|
||||
*/
|
||||
public static function isHealthy(): bool
|
||||
{
|
||||
$lock = self::getLockPath();
|
||||
return file_exists($lock) && trim((string) @file_get_contents($lock)) === \StaticPHP\ConsoleApplication::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write current SPC version to the lock file, marking doctor as passed.
|
||||
*/
|
||||
public static function markPassed(): void
|
||||
{
|
||||
$primary = self::getLockPath();
|
||||
if (!is_dir(dirname($primary))) {
|
||||
@mkdir(dirname($primary), 0755, true);
|
||||
}
|
||||
if (@file_put_contents($primary, \StaticPHP\ConsoleApplication::VERSION) === false) {
|
||||
@file_put_contents((getcwd() ?: '.') . DIRECTORY_SEPARATOR . '.spc-doctor.lock', \StaticPHP\ConsoleApplication::VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all valid check items.
|
||||
* @return bool true if all checks passed, false otherwise
|
||||
@ -119,6 +143,30 @@ readonly class Doctor
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function getLockPath(): string
|
||||
{
|
||||
if (SystemTarget::getTargetOS() === 'Windows') {
|
||||
$trial_ls = [
|
||||
getenv('LOCALAPPDATA') ?: ((getenv('USERPROFILE') ?: 'C:\Users\Default') . '\AppData\Local') . '\.spc-doctor.lock',
|
||||
sys_get_temp_dir() . '\.spc-doctor.lock',
|
||||
WORKING_DIR . '\.spc-doctor.lock',
|
||||
];
|
||||
} else {
|
||||
$trial_ls = [
|
||||
getenv('XDG_CACHE_HOME') ?: ((getenv('HOME') ?: '/tmp') . '/.cache') . '/.spc-doctor.lock',
|
||||
sys_get_temp_dir() . '/.spc-doctor.lock',
|
||||
WORKING_DIR . '/.spc-doctor.lock',
|
||||
];
|
||||
}
|
||||
foreach ($trial_ls as $path) {
|
||||
if (is_writable(dirname($path))) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
// fallback to current directory
|
||||
return WORKING_DIR . DIRECTORY_SEPARATOR . '.spc-doctor.lock';
|
||||
}
|
||||
|
||||
private function emitFix(string $fix_item, array $fix_item_params = []): bool
|
||||
{
|
||||
keyboard_interrupt_register(function () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user