mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-01 15:32:48 +08:00
增加扩展机制定位文件;将common模块实现扩展模式;发布新版本;
This commit is contained in:
313
extend/base/common/command/admin/UpdateBase.php
Normal file
313
extend/base/common/command/admin/UpdateBase.php
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace base\common\command\admin;
|
||||
|
||||
use app\common\command\admin\Version;
|
||||
use app\common\tools\PathTools;
|
||||
use CzProject\GitPhp\Git;
|
||||
use League\Flysystem\Filesystem;
|
||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\App;
|
||||
use think\facade\Env;
|
||||
|
||||
class UpdateBase extends Command
|
||||
{
|
||||
public const REPO = 'https://gitee.com/ulthon/ulthon_admin.git';
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('admin:update')
|
||||
->addOption('reinstall', null, Option::VALUE_NONE, '重装版本')
|
||||
->setDescription('the admin:update command');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
// 指令输出
|
||||
$output->writeln('admin:update');
|
||||
|
||||
$this->cleanWorkpaceDir();
|
||||
|
||||
$current_version = Version::VERSION;
|
||||
|
||||
$current_version_dir = App::getRuntimePath() . '/update/' . $current_version;
|
||||
|
||||
$last_version_dir = App::getRuntimePath() . '/update/last';
|
||||
|
||||
$version_file_regx = "/\bconst VERSION\s*=\s*'[\d\.a-z]+'/";
|
||||
|
||||
$output->writeln('获取最新代码');
|
||||
$last_version_git = new Git();
|
||||
|
||||
$last_version_repo = $last_version_git->cloneRepository(self::REPO, $last_version_dir);
|
||||
|
||||
$tags = $last_version_repo->getTags();
|
||||
|
||||
$update_level = Env::get('adminsystem.update_level', 'production');
|
||||
|
||||
if ($update_level == 'production') {
|
||||
$tags = array_filter($tags, function ($value) {
|
||||
if (strpos($value, '-')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
usort($tags, function ($a, $b) {
|
||||
return version_compare($a, $b);
|
||||
});
|
||||
|
||||
$last_version = $tags[count($tags) - 1];
|
||||
|
||||
if ($last_version == $current_version) {
|
||||
$output->writeln('当前版本为最新版本');
|
||||
$this->cleanWorkpaceDir();
|
||||
|
||||
if ($input->hasOption('reinstall')) {
|
||||
$output->writeln('重装代码');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 将最新代码切换到最新版本,因为最新的提交可能没有发布版本
|
||||
$output->writeln('切换最新代码的最新版本');
|
||||
$last_version_repo->checkout($last_version);
|
||||
|
||||
$current_version_git = new Git();
|
||||
$output->writeln('获取当前版本代码');
|
||||
$current_version_repo = $current_version_git->cloneRepository(self::REPO, $current_version_dir);
|
||||
$output->writeln('切换版本' . $current_version);
|
||||
$current_version_repo->checkout($current_version);
|
||||
|
||||
// 获取当前版本需要跳过的文件
|
||||
$current_version_update_config = include $current_version_dir . '/config/update.php';
|
||||
|
||||
// 获取当前版本要替换的文件
|
||||
$current_version_filesystem = new Filesystem(new LocalFilesystemAdapter($current_version_dir));
|
||||
$current_version_list_files = $current_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
|
||||
->filter(function (StorageAttributes $attributes) use ($current_version_update_config) {
|
||||
if ($attributes->isDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $attributes->path();
|
||||
|
||||
$skip_files = $current_version_update_config['skip_files'] ?? [];
|
||||
|
||||
if (in_array($path, $skip_files)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$skip_dir = $current_version_update_config['skip_dir'] ?? [];
|
||||
$skip_dir[] = '.git';
|
||||
|
||||
foreach ($skip_dir as $dir) {
|
||||
if (str_starts_with($path, $dir)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||
->toArray();
|
||||
|
||||
// 对比现在的代码,检查是否有定制修改
|
||||
|
||||
$output->writeln('对比源码是否被定制');
|
||||
$now_dir = App::getRootPath();
|
||||
|
||||
/**
|
||||
* @var array<bool|string>
|
||||
*/
|
||||
$changed_files = [];
|
||||
|
||||
foreach ($current_version_list_files as $file_path) {
|
||||
$now_file_path = $now_dir . '/' . $file_path;
|
||||
|
||||
$current_version_file_path = $current_version_dir . '/' . $file_path;
|
||||
|
||||
$compare_result = PathTools::compareFiles($now_file_path, $current_version_file_path, true);
|
||||
|
||||
if (!$compare_result || is_string($compare_result)) {
|
||||
$changed_files[$file_path] = $compare_result;
|
||||
}
|
||||
}
|
||||
|
||||
// 有定制修改则退出
|
||||
|
||||
if (!empty($changed_files)) {
|
||||
$output->warning('无法自动更新,以下文件被定制,请还原或手动升级:');
|
||||
|
||||
foreach ($changed_files as $file_path => $compare_result) {
|
||||
$output->warning($file_path);
|
||||
|
||||
if (is_string($compare_result)) {
|
||||
$output->writeln($compare_result);
|
||||
}
|
||||
}
|
||||
|
||||
$file_count = count($changed_files);
|
||||
|
||||
$ask_result = $output->ask($input, "发现{$file_count}个文件被修改,如果您认为以上文件可以被覆盖或为检测错误,可以强制覆盖。\n是否强制继续更新?(y/n)");
|
||||
|
||||
if (!$ask_result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取最新版本需要跳过的文件
|
||||
|
||||
$last_version_skip_config = include $last_version_dir . '/config/update.php';
|
||||
// 获取最新版本要替换的文件
|
||||
$last_version_filesystem = new Filesystem(new LocalFilesystemAdapter($last_version_dir));
|
||||
$last_version_list_files = $last_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
|
||||
->filter(function (StorageAttributes $attributes) use ($last_version_skip_config) {
|
||||
if ($attributes->isDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $attributes->path();
|
||||
|
||||
$skip_files = $last_version_skip_config['skip_files'] ?? [];
|
||||
|
||||
if (in_array($path, $skip_files)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$skip_dir = $last_version_skip_config['skip_dir'] ?? [];
|
||||
$skip_dir[] = '.git';
|
||||
|
||||
foreach ($skip_dir as $dir) {
|
||||
if (str_starts_with($path, $dir)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||
->toArray();
|
||||
|
||||
$delete_files = array_diff($current_version_list_files, $last_version_list_files);
|
||||
|
||||
foreach ($delete_files as $file_path) {
|
||||
$now_file_path = $now_dir . '/' . $file_path;
|
||||
unlink($now_file_path);
|
||||
}
|
||||
|
||||
foreach ($last_version_list_files as $file_path) {
|
||||
$now_file_path = $now_dir . '/' . $file_path;
|
||||
$last_file_path = $last_version_dir . '/' . $file_path;
|
||||
|
||||
$file_content = file_get_contents($last_file_path);
|
||||
|
||||
PathTools::intiDir($now_file_path);
|
||||
file_put_contents($now_file_path, $file_content);
|
||||
}
|
||||
|
||||
// 处理append的文件
|
||||
$last_version_list_skip_files = $last_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
|
||||
->filter(function (StorageAttributes $attributes) use ($last_version_skip_config) {
|
||||
if ($attributes->isDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $attributes->path();
|
||||
|
||||
if (str_starts_with($path, '.git')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$skip_files = $last_version_skip_config['skip_files'] ?? [];
|
||||
|
||||
if (in_array($path, $skip_files)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$skip_dir = $last_version_skip_config['skip_dir'] ?? [];
|
||||
|
||||
foreach ($skip_dir as $dir) {
|
||||
if (str_starts_with($path, $dir)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||
->toArray();
|
||||
|
||||
$last_version_list_append_files = [];
|
||||
|
||||
foreach ($last_version_list_skip_files as $file_path) {
|
||||
if (in_array($file_path, $last_version_skip_config['append_files'])) {
|
||||
$last_version_list_append_files[] = $file_path;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($last_version_skip_config['append_dir'] as $dir) {
|
||||
if (str_starts_with($file_path, $dir)) {
|
||||
$last_version_list_append_files[] = $file_path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($last_version_list_append_files as $file_path) {
|
||||
$now_file_path = $now_dir . '/' . $file_path;
|
||||
$last_file_path = $last_version_dir . '/' . $file_path;
|
||||
|
||||
if (file_exists($now_file_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file_content = file_get_contents($last_file_path);
|
||||
|
||||
PathTools::intiDir($now_file_path);
|
||||
file_put_contents($now_file_path, $file_content);
|
||||
}
|
||||
|
||||
// 检测now的composer依赖和最新的composer依赖
|
||||
|
||||
$last_composer_json = file_get_contents($last_version_dir . '/composer.json');
|
||||
|
||||
$output->writeln($last_composer_json);
|
||||
$output->writeln('请参考以上最新composer文件调整您的依赖');
|
||||
|
||||
// 分析出最新需要的但now没有的
|
||||
|
||||
// 为用户整理出要手动调整的composer命令
|
||||
|
||||
$this->cleanWorkpaceDir();
|
||||
$output->writeln('更新完成');
|
||||
// 更新完成
|
||||
|
||||
if (!empty(Version::UPDATE_TIPS)) {
|
||||
foreach (Version::UPDATE_TIPS as $content) {
|
||||
$output->writeln($content);
|
||||
}
|
||||
$output->writeln('删除对应文件之后,可以通过以下命令重新安装');
|
||||
$output->writeln('php think admin:update --resinstall');
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanWorkpaceDir()
|
||||
{
|
||||
$dir = App::getRuntimePath() . '/update/';
|
||||
|
||||
$this->output->writeln('清理目录 ' . $dir);
|
||||
PathTools::removeDir($dir);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user