mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
add micro:combine command
This commit is contained in:
parent
e522258693
commit
97eff64b5b
116
src/SPC/command/MicroCombineCommand.php
Normal file
116
src/SPC/command/MicroCombineCommand.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('micro:combine', 'Combine micro.sfx and php code together')]
|
||||
class MicroCombineCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined');
|
||||
$this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file');
|
||||
$this->addOption('with-ini-set', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'ini to inject into micro.sfx when combining');
|
||||
$this->addOption('with-ini-file', 'N', InputOption::VALUE_REQUIRED, 'ini file to inject into micro.sfx when combining');
|
||||
$this->addOption('output', 'O', InputOption::VALUE_REQUIRED, 'Customize your output binary file name');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// 0. Initialize path variables
|
||||
$internal = FileSystem::convertPath(BUILD_ROOT_PATH . '/bin/micro.sfx');
|
||||
$micro_file = $this->input->getOption('with-micro');
|
||||
$file = $this->getArgument('file');
|
||||
$ini_set = $this->input->getOption('with-ini-set');
|
||||
$ini_file = $this->input->getOption('with-ini-file');
|
||||
$target_ini = [];
|
||||
$output = $this->input->getOption('output') ?? 'my-app';
|
||||
$ini_part = '';
|
||||
// 1. Make sure specified micro.sfx file exists
|
||||
if ($micro_file !== null && !file_exists($micro_file)) {
|
||||
$this->output->writeln('<error>The micro.sfx file you specified is incorrect or does not exist!</error>');
|
||||
return 1;
|
||||
}
|
||||
// 2. Make sure buildroot/bin/micro.sfx exists
|
||||
if ($micro_file === null && !file_exists($internal)) {
|
||||
$this->output->writeln('<error>You haven\'t compiled micro.sfx yet, please use "build" command and "--build-micro" to compile phpmicro first!</error>');
|
||||
return 1;
|
||||
}
|
||||
// 3. Use buildroot/bin/micro.sfx
|
||||
if ($micro_file === null) {
|
||||
$micro_file = $internal;
|
||||
}
|
||||
// 4. Make sure php or phar file exists
|
||||
if (!is_file(FileSystem::convertPath($file))) {
|
||||
$this->output->writeln('<error>The file to combine does not exist!</error>');
|
||||
return 1;
|
||||
}
|
||||
// 5. Confirm ini files (ini-set has higher priority)
|
||||
if ($ini_file !== null) {
|
||||
// Check file exist first
|
||||
if (!file_exists($ini_file)) {
|
||||
$this->output->writeln('<error>The ini file to combine does not exist! (' . $ini_file . ')</error>');
|
||||
return 1;
|
||||
}
|
||||
$arr = parse_ini_file($ini_file);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>Cannot parse ini file</error>');
|
||||
return 1;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
// 6. Confirm ini sets
|
||||
if ($ini_set !== []) {
|
||||
foreach ($ini_set as $item) {
|
||||
$arr = parse_ini_string($item);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>--with-ini-set parse failed</error>');
|
||||
return 1;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
}
|
||||
// 7. Generate ini injection parts
|
||||
if (!empty($target_ini)) {
|
||||
$ini_str = $this->encodeINI($target_ini);
|
||||
logger()->debug('Injecting ini parts: ' . PHP_EOL . $ini_str);
|
||||
$ini_part = "\xfd\xf6\x69\xe6";
|
||||
$ini_part .= pack('N', strlen($ini_str));
|
||||
$ini_part .= $ini_str;
|
||||
}
|
||||
// 8. Combine !
|
||||
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
|
||||
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
|
||||
$result = file_put_contents($output, $file_target);
|
||||
if ($result === false) {
|
||||
$this->output->writeln('<error>Combine failed.</error>');
|
||||
return 1;
|
||||
}
|
||||
// 9. chmod +x
|
||||
chmod($output, 0755);
|
||||
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function encodeINI(array $array): string
|
||||
{
|
||||
$res = [];
|
||||
foreach ($array as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$res[] = "[{$key}]";
|
||||
foreach ($val as $skey => $sval) {
|
||||
$res[] = "{$skey}=" . (is_numeric($sval) ? $sval : '"' . $sval . '"');
|
||||
}
|
||||
} else {
|
||||
$res[] = "{$key}=" . (is_numeric($val) ? $val : '"' . $val . '"');
|
||||
}
|
||||
}
|
||||
return implode("\n", $res);
|
||||
}
|
||||
}
|
||||
@ -439,6 +439,20 @@ class FileSystem
|
||||
self::$_extract_hook[$name][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the path is a relative path (judging according to whether the first character is "/")
|
||||
*
|
||||
* @param string $path Path
|
||||
*/
|
||||
public static function isRelativePath(string $path): bool
|
||||
{
|
||||
// 适配 Windows 的多盘符目录形式
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return !(strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':');
|
||||
}
|
||||
return strlen($path) > 0 && $path[0] !== '/';
|
||||
}
|
||||
|
||||
private static function emitSourceExtractHook(string $name)
|
||||
{
|
||||
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user