mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-05 17:42:49 +08:00
完成新的更新逻辑
This commit is contained in:
@@ -8,6 +8,8 @@ use CzProject\GitPhp\Git;
|
|||||||
use League\Flysystem\Filesystem;
|
use League\Flysystem\Filesystem;
|
||||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||||
use League\Flysystem\StorageAttributes;
|
use League\Flysystem\StorageAttributes;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\Output;
|
||||||
use think\facade\App;
|
use think\facade\App;
|
||||||
use think\facade\Env;
|
use think\facade\Env;
|
||||||
|
|
||||||
@@ -15,8 +17,14 @@ class AdminUpdateServiceBase
|
|||||||
{
|
{
|
||||||
public const REPO = 'https://gitee.com/ulthon/ulthon_admin.git';
|
public const REPO = 'https://gitee.com/ulthon/ulthon_admin.git';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Input
|
||||||
|
*/
|
||||||
public $input;
|
public $input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Output
|
||||||
|
*/
|
||||||
public $output;
|
public $output;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
@@ -84,32 +92,57 @@ class AdminUpdateServiceBase
|
|||||||
$output->writeln('切换版本' . $current_version);
|
$output->writeln('切换版本' . $current_version);
|
||||||
$current_version_repo->checkout($current_version);
|
$current_version_repo->checkout($current_version);
|
||||||
|
|
||||||
// 获取当前版本需要跳过的文件
|
$output->writeln('开始比较版本差异');
|
||||||
$current_version_update_config = include $current_version_dir . '/config/update.php';
|
|
||||||
|
|
||||||
// 获取当前版本要替换的文件
|
|
||||||
$current_version_filesystem = new Filesystem(new LocalFilesystemAdapter($current_version_dir));
|
$current_version_filesystem = new Filesystem(new LocalFilesystemAdapter($current_version_dir));
|
||||||
$current_version_list_files = $current_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
|
$last_version_filesystem = new Filesystem(new LocalFilesystemAdapter($last_version_dir));
|
||||||
->filter(function (StorageAttributes $attributes) use ($current_version_update_config) {
|
|
||||||
|
// app、config下的所有文件和根目录下的几个文件
|
||||||
|
// 如果与当前版本一致(没有定制过),则将这种文件增加到完全跟踪列表,(新版覆盖、新版删除),
|
||||||
|
// 否则不会覆盖和删除,但会将新文件追加到相应目录下
|
||||||
|
|
||||||
|
// 其余的所有代码都应当完全跟踪
|
||||||
|
|
||||||
|
// 完全跳过runtime、vendor、.git目录
|
||||||
|
|
||||||
|
$list_optional_update_files = [];
|
||||||
|
|
||||||
|
$list_optional_update_files = array_merge(
|
||||||
|
$list_optional_update_files,
|
||||||
|
$current_version_filesystem->listContents('/app', true)
|
||||||
|
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||||
|
->toArray()
|
||||||
|
);
|
||||||
|
$list_optional_update_files = array_merge(
|
||||||
|
$list_optional_update_files,
|
||||||
|
$current_version_filesystem->listContents('/config', true)
|
||||||
|
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||||
|
->toArray()
|
||||||
|
);
|
||||||
|
$list_optional_update_files = array_merge(
|
||||||
|
$list_optional_update_files,
|
||||||
|
$current_version_filesystem->listContents('/')
|
||||||
|
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||||
|
->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 当前版本的所有文件
|
||||||
|
$current_version_files = $current_version_filesystem->listContents('/', true)
|
||||||
|
->filter(function (StorageAttributes $attributes) {
|
||||||
if ($attributes->isDir()) {
|
if ($attributes->isDir()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $attributes->path();
|
if (strpos($attributes->path(), 'runtime') === 0) {
|
||||||
|
|
||||||
$skip_files = $current_version_update_config['skip_files'] ?? [];
|
|
||||||
|
|
||||||
if (in_array($path, $skip_files)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$skip_dir = $current_version_update_config['skip_dir'] ?? [];
|
if (strpos($attributes->path(), 'vendor') === 0) {
|
||||||
$skip_dir[] = '.git';
|
|
||||||
|
|
||||||
foreach ($skip_dir as $dir) {
|
|
||||||
if (str_starts_with($path, $dir)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strpos($attributes->path(), '.git') === 0) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -117,160 +150,133 @@ class AdminUpdateServiceBase
|
|||||||
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
// 对比现在的代码,检查是否有定制修改
|
// 最新版本的所有文件
|
||||||
|
$last_version_files = $last_version_filesystem->listContents('/', true)
|
||||||
|
->filter(function (StorageAttributes $attributes) {
|
||||||
|
if ($attributes->isDir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$output->writeln('对比源码是否被定制');
|
if (strpos($attributes->path(), 'runtime') === 0) {
|
||||||
$now_dir = App::getRootPath();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($attributes->path(), 'vendor') === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
->map(fn (StorageAttributes $attributes) => $attributes->path())
|
||||||
|
->toArray();
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array<bool|string>
|
|
||||||
*/
|
|
||||||
$changed_files = [];
|
$changed_files = [];
|
||||||
|
|
||||||
foreach ($current_version_list_files as $file_path) {
|
// 需要删除的文件
|
||||||
|
$need_delete_files = array_diff($current_version_files, $last_version_files);
|
||||||
|
|
||||||
|
foreach ($need_delete_files as $file_path) {
|
||||||
|
$changed_files[$file_path] = 'delete';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 需要增加的文件
|
||||||
|
$need_add_files = array_diff($last_version_files, $current_version_files);
|
||||||
|
|
||||||
|
foreach ($need_add_files as $file_path) {
|
||||||
|
$changed_files[$file_path] = 'add';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 需要更新的文件
|
||||||
|
$need_update_files = array_intersect($current_version_files, $last_version_files);
|
||||||
|
|
||||||
|
foreach ($need_update_files as $file_path) {
|
||||||
|
$changed_files[$file_path] = 'update';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示用户有一些完全跟踪的文件被修改了
|
||||||
|
|
||||||
|
$optional_update_waring_files = [];
|
||||||
|
$force_update_waring_files = [];
|
||||||
|
|
||||||
|
$now_dir = App::getRootPath();
|
||||||
|
|
||||||
|
$need_process_files = [];
|
||||||
|
|
||||||
|
foreach ($changed_files as $file_path => $type) {
|
||||||
$now_file_path = $now_dir . '/' . $file_path;
|
$now_file_path = $now_dir . '/' . $file_path;
|
||||||
|
$current_file_path = $current_version_dir . '/' . $file_path;
|
||||||
|
$last_file_path = $last_version_dir . '/' . $file_path;
|
||||||
|
|
||||||
$current_version_file_path = $current_version_dir . '/' . $file_path;
|
// 如果新老版本文件一致,则不需要处理
|
||||||
|
if (PathTools::compareFiles($current_file_path, $last_file_path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$compare_result = PathTools::compareFiles($now_file_path, $current_version_file_path, true);
|
if (in_array($file_path, $list_optional_update_files)) {
|
||||||
|
// 可选的文件没有被定制,需要跟踪变化,需要提醒
|
||||||
if (!$compare_result) {
|
if (PathTools::compareFiles($now_file_path, $current_file_path)) {
|
||||||
$changed_files[$file_path] = $compare_result;
|
$optional_update_waring_files[$file_path] = $type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 强制更新的文件被定制了,需要提醒
|
||||||
|
if (!PathTools::compareFiles($now_file_path, $current_file_path)) {
|
||||||
|
$force_update_waring_files[$file_path] = $type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 有定制修改则退出
|
if (!empty($optional_update_waring_files)) {
|
||||||
|
foreach ($optional_update_waring_files as $file_path => $type) {
|
||||||
|
$output->writeln($file_path . ' ' . $type);
|
||||||
|
}
|
||||||
|
$output->writeln('以上文件没有被您定制,您可以放心更新文件,');
|
||||||
|
$output->writeln('但此目录原则上应当由您手动处理,如果您使用了以下文件,可能会发生错误,');
|
||||||
|
$output->writeln('如果您没有关心过这些文件,您可以放心更新。');
|
||||||
|
|
||||||
if (!empty($changed_files)) {
|
$is_udpate_optinal_files = $output->ask($input, '确定要更新吗?', true);
|
||||||
$output->warning('无法自动更新,以下文件被定制,请还原或手动升级:');
|
|
||||||
|
|
||||||
foreach ($changed_files as $file_path => $compare_result) {
|
if ($is_udpate_optinal_files) {
|
||||||
$output->warning($file_path);
|
$need_process_files = array_merge($need_process_files, $optional_update_waring_files);
|
||||||
|
|
||||||
if (is_string($compare_result)) {
|
|
||||||
$output->writeln($compare_result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$file_count = count($changed_files);
|
if (!empty($force_update_waring_files)) {
|
||||||
|
foreach ($force_update_waring_files as $file_path => $type) {
|
||||||
|
$output->writeln($file_path . ' ' . $type);
|
||||||
|
}
|
||||||
|
$output->writeln('以上文件被您定制了,您不应该修改这些文件,');
|
||||||
|
$output->writeln('但您出于某些原因修改了他们,如果继续更新,则会覆盖至最新版本,');
|
||||||
|
$output->writeln('这些改动不应该发生,继续自动升级可能会导致错误');
|
||||||
|
|
||||||
$ask_result = $output->ask($input, "发现{$file_count}个文件被修改,如果您认为以上文件可以被覆盖或为检测错误,可以强制覆盖。\n是否强制继续更新?(y/n)");
|
$is_udpate_force_files = $output->ask($input, '确定要更新吗?', false);
|
||||||
|
|
||||||
if (!$ask_result) {
|
if ($is_udpate_force_files) {
|
||||||
|
$need_process_files = array_merge($need_process_files, $force_update_waring_files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($need_process_files)){
|
||||||
|
$output->writeln('没有需要更新的文件');
|
||||||
|
$this->cleanWorkpaceDir();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 获取最新版本需要跳过的文件
|
// 处理需要更新的文件
|
||||||
|
|
||||||
$last_version_skip_config = include $last_version_dir . '/config/update.php';
|
foreach ($need_process_files as $file_path => $type) {
|
||||||
// 获取最新版本要替换的文件
|
|
||||||
$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;
|
$now_file_path = $now_dir . '/' . $file_path;
|
||||||
|
$last_file_path = $last_version_dir . '/' . $file_path;
|
||||||
|
|
||||||
|
if ($type == 'delete') {
|
||||||
|
$output->writeln('删除文件' . $now_file_path);
|
||||||
unlink($now_file_path);
|
unlink($now_file_path);
|
||||||
|
} elseif ($type == 'add') {
|
||||||
|
$output->writeln('增加文件' . $now_file_path);
|
||||||
|
copy($last_file_path, $now_file_path);
|
||||||
|
} elseif ($type == 'update') {
|
||||||
|
$output->writeln('更新文件' . $now_file_path);
|
||||||
|
copy($last_file_path, $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依赖
|
// 检测now的composer依赖和最新的composer依赖
|
||||||
|
|||||||
@@ -104,6 +104,13 @@ class PathToolsBase
|
|||||||
return str_replace('/', '\\', $content);
|
return str_replace('/', '\\', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个文件是否相同
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
* @return boolean 如果一致返回true,否则返回false
|
||||||
|
*/
|
||||||
public static function compareFiles($a, $b):bool
|
public static function compareFiles($a, $b):bool
|
||||||
{
|
{
|
||||||
if (file_exists($a) !== file_exists($b)) {
|
if (file_exists($a) !== file_exists($b)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user