mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-10 10:25:36 +08:00
v3 base
This commit is contained in:
180
src/StaticPHP/Command/BaseCommand.php
Normal file
180
src/StaticPHP/Command/BaseCommand.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Exception\ExceptionHandler;
|
||||
use StaticPHP\Exception\SPCException;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
abstract class BaseCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The message of the day (MOTD) displayed when the command is run.
|
||||
* You can customize this to show your application's name and version if you are using SPC in vendor mode.
|
||||
*/
|
||||
public static string $motd = ' ____ _ _ _ ____ _ _ ____
|
||||
/ ___|| |_ __ _| |_(_) ___| _ \| | | | _ \
|
||||
\___ \| __/ _` | __| |/ __| |_) | |_| | |_) |
|
||||
___) | || (_| | |_| | (__| __/| _ | __/
|
||||
|____/ \__\__,_|\__|_|\___|_| |_| |_|_| v{version}
|
||||
|
||||
';
|
||||
|
||||
protected bool $no_motd = false;
|
||||
|
||||
protected InputInterface $input;
|
||||
|
||||
protected OutputInterface $output;
|
||||
|
||||
public function __construct(?string $name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->addOption('debug', null, null, '(deprecated) Enable debug mode');
|
||||
$this->addOption('no-motd', null, null, 'Disable motd');
|
||||
}
|
||||
|
||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
||||
// Bind command context to ApplicationContext
|
||||
ApplicationContext::bindCommandContext($input, $output);
|
||||
|
||||
if ($input->getOption('no-motd')) {
|
||||
$this->no_motd = true;
|
||||
}
|
||||
|
||||
set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) {
|
||||
$tips = [
|
||||
E_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_USER_ERROR => ['PHP Error: ', 'error'],
|
||||
E_USER_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
|
||||
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
|
||||
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
|
||||
];
|
||||
$level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error'];
|
||||
$error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
|
||||
logger()->{$level_tip[1]}($error);
|
||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||
return true;
|
||||
});
|
||||
$version = $this->getVersionWithCommit();
|
||||
if (!$this->no_motd) {
|
||||
echo str_replace('{version}', $version, self::$motd);
|
||||
}
|
||||
}
|
||||
|
||||
abstract public function handle(): int;
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
try {
|
||||
// handle verbose option
|
||||
$level = match ($this->output->getVerbosity()) {
|
||||
OutputInterface::VERBOSITY_VERBOSE => 'info',
|
||||
OutputInterface::VERBOSITY_VERY_VERBOSE, OutputInterface::VERBOSITY_DEBUG => 'debug',
|
||||
default => 'warning',
|
||||
};
|
||||
logger()->setLevel($level);
|
||||
|
||||
// ansi
|
||||
if ($this->input->getOption('no-ansi')) {
|
||||
logger()->setDecorated(false);
|
||||
}
|
||||
|
||||
// Set debug mode in ApplicationContext
|
||||
$isDebug = $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
|
||||
ApplicationContext::setDebug($isDebug);
|
||||
|
||||
// show raw argv list for logger()->debug
|
||||
logger()->debug('argv: ' . implode(' ', $_SERVER['argv']));
|
||||
return $this->handle();
|
||||
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (SPCException $e) {
|
||||
// Handle SPCException and log it
|
||||
ExceptionHandler::handleSPCException($e);
|
||||
return static::FAILURE;
|
||||
} catch (\Throwable $e) {
|
||||
// Handle any other exceptions
|
||||
ExceptionHandler::handleDefaultException($e);
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getOption(string $name): mixed
|
||||
{
|
||||
return $this->input->getOption($name);
|
||||
}
|
||||
|
||||
protected function getArgument(string $name): mixed
|
||||
{
|
||||
return $this->input->getArgument($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get version string with git commit short ID if available.
|
||||
*/
|
||||
private function getVersionWithCommit(): string
|
||||
{
|
||||
$version = $this->getApplication()->getVersion();
|
||||
|
||||
// Don't show commit ID when running in phar
|
||||
if (\Phar::running()) {
|
||||
return $version;
|
||||
}
|
||||
|
||||
$commitId = $this->getGitCommitShortId();
|
||||
if ($commitId) {
|
||||
return "{$version} ({$commitId})";
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get git commit short ID without executing git command.
|
||||
*/
|
||||
private function getGitCommitShortId(): ?string
|
||||
{
|
||||
try {
|
||||
$gitDir = ROOT_DIR . '/.git';
|
||||
|
||||
if (!is_dir($gitDir)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$headFile = $gitDir . '/HEAD';
|
||||
if (!file_exists($headFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$head = trim(file_get_contents($headFile));
|
||||
|
||||
// If HEAD contains 'ref:', it's a branch reference
|
||||
if (str_starts_with($head, 'ref: ')) {
|
||||
$ref = substr($head, 5);
|
||||
$refFile = $gitDir . '/' . $ref;
|
||||
|
||||
if (file_exists($refFile)) {
|
||||
$commit = trim(file_get_contents($refFile));
|
||||
return substr($commit, 0, 7);
|
||||
}
|
||||
} else {
|
||||
// HEAD contains the commit hash directly (detached HEAD)
|
||||
return substr($head, 0, 7);
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Silently fail if we can't read git info
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
src/StaticPHP/Command/BuildLibsCommand.php
Normal file
29
src/StaticPHP/Command/BuildLibsCommand.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
#[AsCommand('build:libs')]
|
||||
class BuildLibsCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addArgument('libraries', InputArgument::REQUIRED, 'The library packages will be compiled, comma separated');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$libs = parse_comma_list($this->input->getArgument('libraries'));
|
||||
|
||||
$installer = new \StaticPHP\Package\PackageInstaller($this->input->getOptions());
|
||||
foreach ($libs as $lib) {
|
||||
$installer->addBuildPackage($lib);
|
||||
}
|
||||
$installer->run();
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
56
src/StaticPHP/Command/BuildTargetCommand.php
Normal file
56
src/StaticPHP/Command/BuildTargetCommand.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Artifact\DownloaderOptions;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PackageLoader;
|
||||
use StaticPHP\Util\V2CompatLayer;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class BuildTargetCommand extends BaseCommand
|
||||
{
|
||||
public function __construct(private readonly string $target, ?string $description = null)
|
||||
{
|
||||
parent::__construct("build:{$target}");
|
||||
if ($target === 'php') {
|
||||
$this->setAliases(['build']);
|
||||
}
|
||||
$this->setDescription($description ?? "Build {$target} target from source");
|
||||
$pkg = PackageLoader::getTargetPackage($target);
|
||||
$this->getDefinition()->addOptions($pkg->_exportBuildOptions());
|
||||
$this->getDefinition()->addArguments($pkg->_exportBuildArguments());
|
||||
|
||||
// Builder options
|
||||
$this->getDefinition()->addOptions([
|
||||
new InputOption('with-suggests', ['L', 'E'], null, 'Resolve and install suggested packages as well'),
|
||||
new InputOption('with-packages', null, InputOption::VALUE_REQUIRED, 'add additional packages to install/build, comma separated', ''),
|
||||
new InputOption('no-download', null, null, 'Skip downloading artifacts (use existing cached files)'),
|
||||
...V2CompatLayer::getLegacyBuildOptions(),
|
||||
]);
|
||||
|
||||
// Downloader options (with 'dl-' prefix to avoid conflicts)
|
||||
$this->getDefinition()->addOptions(DownloaderOptions::getConsoleOptions('dl'));
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// resolve legacy options to new options
|
||||
V2CompatLayer::convertOptions($this->input);
|
||||
|
||||
$starttime = microtime(true);
|
||||
// run installer
|
||||
$installer = new PackageInstaller($this->input->getOptions());
|
||||
$installer->addBuildPackage($this->target);
|
||||
$installer->run();
|
||||
|
||||
$usedtime = round(microtime(true) - $starttime, 1);
|
||||
$this->output->writeln("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
$this->output->writeln("<info>✔ BUILD SUCCESSFUL ({$usedtime} s)</info>");
|
||||
$this->output->writeln("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
34
src/StaticPHP/Command/DoctorCommand.php
Normal file
34
src/StaticPHP/Command/DoctorCommand.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Doctor\Doctor;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')]
|
||||
class DoctorCommand extends BaseCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addOption('auto-fix', null, InputOption::VALUE_OPTIONAL, 'Automatically fix failed items (if possible)', false);
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$fix_policy = match ($this->input->getOption('auto-fix')) {
|
||||
'never' => FIX_POLICY_DIE,
|
||||
true, null => FIX_POLICY_AUTOFIX,
|
||||
default => FIX_POLICY_PROMPT,
|
||||
};
|
||||
$doctor = new Doctor($this->output, $fix_policy);
|
||||
if ($doctor->checkAll()) {
|
||||
$this->output->writeln('<info>Doctor check complete !</info>');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
116
src/StaticPHP/Command/DownloadCommand.php
Normal file
116
src/StaticPHP/Command/DownloadCommand.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Artifact\ArtifactDownloader;
|
||||
use StaticPHP\Artifact\DownloaderOptions;
|
||||
use StaticPHP\Package\PackageLoader;
|
||||
use StaticPHP\Util\DependencyResolver;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\InteractiveTerm;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('download')]
|
||||
class DownloadCommand extends BaseCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addArgument('artifacts', InputArgument::OPTIONAL, 'Specific artifacts to download, comma separated, e.g "php-src,openssl,curl"');
|
||||
|
||||
// 2.x compatible options
|
||||
$this->addOption('shallow-clone', null, null, '(deprecated) Clone shallowly repositories when downloading sources');
|
||||
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
|
||||
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
|
||||
$this->addOption('without-suggests', null, null, 'Do not fetch suggested sources when using --for-extensions');
|
||||
|
||||
// download command specific options
|
||||
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
||||
$this->addOption('for-packages', null, InputOption::VALUE_REQUIRED, 'Fetch by packages, e.g "php,libssl,libcurl"');
|
||||
|
||||
// shared downloader options (no prefix for download command)
|
||||
$this->getDefinition()->addOptions(DownloaderOptions::getConsoleOptions());
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// handle --clean option
|
||||
if ($this->getOption('clean')) {
|
||||
return $this->handleClean();
|
||||
}
|
||||
|
||||
$downloader = new ArtifactDownloader(DownloaderOptions::extractFromConsoleOptions($this->input->getOptions()));
|
||||
|
||||
// arguments
|
||||
if ($artifacts = $this->getArgument('artifacts')) {
|
||||
$artifacts = parse_comma_list($artifacts);
|
||||
$downloader->addArtifacts($artifacts);
|
||||
}
|
||||
// for-extensions
|
||||
$packages = [];
|
||||
if ($exts = $this->getOption('for-extensions')) {
|
||||
$packages = array_map(fn ($x) => "ext-{$x}", parse_extension_list($exts));
|
||||
// when using for-extensions, also include php package
|
||||
array_unshift($packages, 'php');
|
||||
array_unshift($packages, 'php-micro');
|
||||
array_unshift($packages, 'php-embed');
|
||||
array_unshift($packages, 'php-fpm');
|
||||
}
|
||||
// for-libs / for-packages
|
||||
if ($libs = $this->getOption('for-libs')) {
|
||||
$packages = array_merge($packages, parse_comma_list($libs));
|
||||
}
|
||||
if ($libs = $this->getOption('for-packages')) {
|
||||
$packages = array_merge($packages, parse_comma_list($libs));
|
||||
}
|
||||
|
||||
// resolve package dependencies and get artifacts directly
|
||||
$resolved = DependencyResolver::resolve($packages, [], !$this->getOption('without-suggests'));
|
||||
foreach ($resolved as $pkg_name) {
|
||||
$pkg = PackageLoader::getPackage($pkg_name);
|
||||
if ($artifact = $pkg->getArtifact()) {
|
||||
$downloader->add($artifact);
|
||||
}
|
||||
}
|
||||
$starttime = microtime(true);
|
||||
$downloader->download();
|
||||
|
||||
$endtime = microtime(true);
|
||||
$elapsed = round($endtime - $starttime);
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<info>Download completed in ' . $elapsed . ' s.</info>');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function handleClean(): int
|
||||
{
|
||||
logger()->warning('You are doing some operations that are not recoverable:');
|
||||
logger()->warning('- Removing directory: ' . SOURCE_PATH);
|
||||
logger()->warning('- Removing directory: ' . DOWNLOAD_PATH);
|
||||
logger()->warning('- Removing directory: ' . BUILD_ROOT_PATH);
|
||||
logger()->alert('I will remove these directories after 5 seconds!');
|
||||
sleep(5);
|
||||
|
||||
if (is_dir(SOURCE_PATH)) {
|
||||
InteractiveTerm::indicateProgress('Removing: ' . SOURCE_PATH);
|
||||
FileSystem::removeDir(SOURCE_PATH);
|
||||
InteractiveTerm::finish('Removed: ' . SOURCE_PATH);
|
||||
}
|
||||
if (is_dir(DOWNLOAD_PATH)) {
|
||||
InteractiveTerm::indicateProgress('Removing: ' . DOWNLOAD_PATH);
|
||||
FileSystem::removeDir(DOWNLOAD_PATH);
|
||||
InteractiveTerm::finish('Removed: ' . DOWNLOAD_PATH);
|
||||
}
|
||||
if (is_dir(BUILD_ROOT_PATH)) {
|
||||
InteractiveTerm::indicateProgress('Removing: ' . BUILD_ROOT_PATH);
|
||||
FileSystem::removeDir(BUILD_ROOT_PATH);
|
||||
InteractiveTerm::finish('Removed: ' . BUILD_ROOT_PATH);
|
||||
}
|
||||
|
||||
InteractiveTerm::notice('Clean completed.');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
108
src/StaticPHP/Command/ExtractCommand.php
Normal file
108
src/StaticPHP/Command/ExtractCommand.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Artifact\ArtifactCache;
|
||||
use StaticPHP\Artifact\ArtifactExtractor;
|
||||
use StaticPHP\Artifact\ArtifactLoader;
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Package\PackageLoader;
|
||||
use StaticPHP\Util\DependencyResolver;
|
||||
use StaticPHP\Util\InteractiveTerm;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use ZM\Logger\ConsoleColor;
|
||||
|
||||
#[AsCommand('extract')]
|
||||
class ExtractCommand extends BaseCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->setDescription('Extract downloaded artifacts to their target locations');
|
||||
|
||||
$this->addArgument('artifacts', InputArgument::OPTIONAL, 'Specific artifacts to extract, comma separated, e.g "php-src,openssl,curl"');
|
||||
|
||||
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Extract artifacts for extensions, e.g "openssl,mbstring"');
|
||||
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Extract artifacts for libraries, e.g "libcares,openssl"');
|
||||
$this->addOption('for-packages', null, InputOption::VALUE_REQUIRED, 'Extract artifacts for packages, e.g "php,libssl,libcurl"');
|
||||
$this->addOption('without-suggests', null, null, 'Do not include suggested packages when using --for-extensions');
|
||||
$this->addOption('force-source', null, null, 'Force extract source even if binary is available');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$cache = ApplicationContext::get(ArtifactCache::class);
|
||||
$extractor = new ArtifactExtractor($cache);
|
||||
$force_source = (bool) $this->getOption('force-source');
|
||||
|
||||
$artifacts = [];
|
||||
|
||||
// Direct artifact names
|
||||
if ($artifact_arg = $this->getArgument('artifacts')) {
|
||||
$artifact_names = parse_comma_list($artifact_arg);
|
||||
foreach ($artifact_names as $name) {
|
||||
$artifact = ArtifactLoader::getArtifactInstance($name);
|
||||
if ($artifact === null) {
|
||||
$this->output->writeln("<error>Artifact '{$name}' not found.</error>");
|
||||
return static::FAILURE;
|
||||
}
|
||||
$artifacts[$name] = $artifact;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve packages and get their artifacts
|
||||
$packages = [];
|
||||
if ($exts = $this->getOption('for-extensions')) {
|
||||
$packages = array_map(fn ($x) => "ext-{$x}", parse_extension_list($exts));
|
||||
// Include php package when using for-extensions
|
||||
array_unshift($packages, 'php');
|
||||
}
|
||||
if ($libs = $this->getOption('for-libs')) {
|
||||
$packages = array_merge($packages, parse_comma_list($libs));
|
||||
}
|
||||
if ($pkgs = $this->getOption('for-packages')) {
|
||||
$packages = array_merge($packages, parse_comma_list($pkgs));
|
||||
}
|
||||
|
||||
if (!empty($packages)) {
|
||||
$resolved = DependencyResolver::resolve($packages, [], !$this->getOption('without-suggests'));
|
||||
foreach ($resolved as $pkg_name) {
|
||||
$pkg = PackageLoader::getPackage($pkg_name);
|
||||
if ($artifact = $pkg->getArtifact()) {
|
||||
$artifacts[$artifact->getName()] = $artifact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($artifacts)) {
|
||||
$this->output->writeln('<comment>No artifacts specified. Use artifact names or --for-extensions/--for-libs/--for-packages options.</comment>');
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('Examples:');
|
||||
$this->output->writeln(' spc extract php-src,openssl');
|
||||
$this->output->writeln(' spc extract --for-extensions=openssl,mbstring');
|
||||
$this->output->writeln(' spc extract --for-libs=libcurl,libssl');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
// make php-src always extracted first
|
||||
uksort($artifacts, fn ($a, $b) => $a === 'php-src' ? -1 : ($b === 'php-src' ? 1 : 0));
|
||||
|
||||
try {
|
||||
InteractiveTerm::notice('Extracting ' . count($artifacts) . ' artifacts: ' . implode(',', array_map(fn ($x) => ConsoleColor::yellow($x->getName()), $artifacts)) . '...');
|
||||
InteractiveTerm::indicateProgress('Extracting artifacts');
|
||||
foreach ($artifacts as $artifact) {
|
||||
InteractiveTerm::setMessage('Extracting artifact: ' . ConsoleColor::green($artifact->getName()));
|
||||
$extractor->extract($artifact, $force_source);
|
||||
}
|
||||
InteractiveTerm::finish('Extracted all artifacts successfully.');
|
||||
} catch (\Exception $e) {
|
||||
InteractiveTerm::finish('Extraction failed!', false);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
27
src/StaticPHP/Command/InstallPackageCommand.php
Normal file
27
src/StaticPHP/Command/InstallPackageCommand.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand('install-pkg')]
|
||||
class InstallPackageCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addArgument('package', null, 'The package to install (name or path)');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
ApplicationContext::set('elephant', true);
|
||||
$installer = new PackageInstaller([...$this->input->getOptions(), 'dl-prefer-binary' => true]);
|
||||
$installer->addInstallPackage($this->input->getArgument('package'));
|
||||
$installer->run(true, true);
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
56
src/StaticPHP/Command/SPCConfigCommand.php
Normal file
56
src/StaticPHP/Command/SPCConfigCommand.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Util\SPCConfigUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('spc-config', 'Build dependencies')]
|
||||
class SPCConfigCommand extends BaseCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addArgument('extensions', InputArgument::OPTIONAL, 'The extensions will be compiled, comma separated');
|
||||
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
||||
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
||||
$this->addOption('with-suggests', null, null, 'Build with suggested packages for selected exts and libs');
|
||||
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
||||
$this->addOption('includes', null, null, 'Add additional include path');
|
||||
$this->addOption('libs', null, null, 'Add additional libs path');
|
||||
$this->addOption('libs-only-deps', null, null, 'Output dependent libraries with -l prefix');
|
||||
$this->addOption('absolute-libs', null, null, 'Output absolute paths for libraries');
|
||||
$this->addOption('no-php', null, null, 'Link to PHP library');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// transform string to array
|
||||
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
|
||||
// transform string to array
|
||||
$extensions = $this->getArgument('extensions') ? parse_extension_list($this->getArgument('extensions')) : [];
|
||||
$include_suggests = $this->getOption('with-suggests') ?: $this->getOption('with-suggested-libs') || $this->getOption('with-suggested-exts');
|
||||
|
||||
$util = new SPCConfigUtil(options: [
|
||||
'no_php' => $this->getOption('no-php'),
|
||||
'libs_only_deps' => $this->getOption('libs-only-deps'),
|
||||
'absolute_libs' => $this->getOption('absolute-libs'),
|
||||
]);
|
||||
$packages = array_merge(array_map(fn ($x) => "ext-{$x}", $extensions), $libraries);
|
||||
$config = $util->config($packages, $include_suggests);
|
||||
|
||||
$this->output->writeln(match (true) {
|
||||
$this->getOption('includes') => $config['cflags'],
|
||||
$this->getOption('libs-only-deps') => $config['libs'],
|
||||
$this->getOption('libs') => "{$config['ldflags']} {$config['libs']}",
|
||||
default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}",
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user