chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace ywxapp\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\App;
|
||||
use ywxapp\service\FrameworkService;
|
||||
use ywxapp\service\AddonService;
|
||||
|
||||
/**
|
||||
* 一键离线升级命令(手动执行升级)
|
||||
*
|
||||
* 用于绕过在线下载,直接对本地打包产物执行升级:
|
||||
* - 框架核心包 / 框架整站包 → 复用 FrameworkService::apply(解压、备份、跑 upgrade.sql、写版本号)
|
||||
* - 插件包 → 复用 AddonService::local(解压覆盖、导入 install.sql、重导菜单)
|
||||
*
|
||||
* 用法:
|
||||
* # 框架核心补丁包(剥离 ywxapp/ 前缀,解压到 ywxapp/)
|
||||
* php think ywxapp:upgrade --file=runtime/framework/ywxapp-1.0.9.zip --ver=1.0.9 --type=framework --patch
|
||||
* # 框架整站包(不解前缀,解压到项目根)
|
||||
* php think ywxapp:upgrade --file=runtime/framework/ywxapp-1.0.9.zip --ver=1.0.9 --type=framework
|
||||
* # 插件升级(zip 根已是插件内容)
|
||||
* php think ywxapp:upgrade --file=runtime/market/forum-1.0.1.zip --type=addon
|
||||
*
|
||||
* 说明:
|
||||
* - 框架 --ver 必填(写入 config/ywxapp.php);插件版本从 zip 内 info.php 自动读取。
|
||||
* - 命令执行前会自动备份(FrameworkService 备份到 runtime/framework/backup;AddonService 备份到 runtime/addon)。
|
||||
*/
|
||||
class Upgrade extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('ywxapp:upgrade')
|
||||
->addOption('file', 'f', Option::VALUE_REQUIRED, '升级包本地路径(zip)')
|
||||
->addOption('type', 't', Option::VALUE_REQUIRED, '类型: framework | addon')
|
||||
->addOption('ver', 'r', Option::VALUE_OPTIONAL, '目标版本号(framework 必填;addon 自动读取)')
|
||||
->addOption('patch', 'p', Option::VALUE_NONE, '框架补丁包(核心包,剥离 ywxapp/ 前缀;整站包勿加)')
|
||||
->setDescription('本地离线升级:框架核心/整站包或插件包一键手动执行');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output): int
|
||||
{
|
||||
$file = trim((string) $input->getOption('file'));
|
||||
$type = strtolower(trim((string) $input->getOption('type')));
|
||||
$version = trim((string) $input->getOption('ver'));
|
||||
$isPatch = (bool) $input->getOption('patch');
|
||||
|
||||
if ($file === '' || !is_file($file)) {
|
||||
$output->writeln('<error>请通过 --file 指定存在的 zip 路径</error>');
|
||||
return 1;
|
||||
}
|
||||
if (!in_array($type, ['framework', 'addon'], true)) {
|
||||
$output->writeln('<error>--type 必须是 framework 或 addon</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($type === 'framework') {
|
||||
if ($version === '') {
|
||||
$output->writeln('<error>framework 升级需通过 --version 指定目标版本号</error>');
|
||||
return 1;
|
||||
}
|
||||
$output->writeln("<info>开始升级框架到 {$version}(" . ($isPatch ? '补丁包' : '整站包') . ")...</info>");
|
||||
$svc = App::getInstance()->make(FrameworkService::class);
|
||||
$res = $svc->apply($file, $version, $isPatch ? 1 : 0);
|
||||
$output->writeln('<info>框架升级完成:' . ($res['msg'] ?? 'ok') . '</info>');
|
||||
} else {
|
||||
$output->writeln("<info>开始升级插件({$file})...</info>");
|
||||
// 从 zip 内 info.php 解析插件名,用于实例化 AddonService(需先确定 addonDir)
|
||||
$addonName = $this->readAddonNameFromZip($file);
|
||||
if ($addonName === '') {
|
||||
$output->writeln('<error>无法从升级包内 info.php 解析插件名</error>');
|
||||
return 1;
|
||||
}
|
||||
// 构造 think\File 对象(real 路径,足够 validate/upload 使用)
|
||||
$fileObj = new \think\File($file);
|
||||
$svc = new AddonService($addonName);
|
||||
$res = $svc->localUpgrade($fileObj);
|
||||
$output->writeln('<info>插件升级完成:' . $addonName
|
||||
. ' ' . ($res['from'] ?? '') . ' -> ' . ($res['to'] ?? '') . '</info>');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$output->writeln('<error>升级失败:' . $e->getMessage() . '</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$output->writeln('<comment>建议随后清理缓存:删除 runtime/cache、runtime/temp</comment>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从升级包 zip 内 info.php 解析插件名
|
||||
*
|
||||
* @param string $zipFile
|
||||
* @return string
|
||||
*/
|
||||
private function readAddonNameFromZip(string $zipFile): string
|
||||
{
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($zipFile) !== true) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
// 寻找包内 info.php(可能位于根目录或 <addon>/info.php)
|
||||
$name = '';
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$entry = $zip->getNameIndex($i);
|
||||
if (basename($entry) === 'info.php' && substr($entry, -strlen('info.php')) === 'info.php') {
|
||||
$content = $zip->getFromIndex($i);
|
||||
if ($content !== false && preg_match("/'name'\s*=>\s*'([^']+)'/", $content, $m)) {
|
||||
$name = $m[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $name;
|
||||
} finally {
|
||||
$zip->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user