diff --git a/.example.env b/.example.env index 1b2c691..e28af9c 100644 --- a/.example.env +++ b/.example.env @@ -53,4 +53,6 @@ DEFAULT_AUTH_CHECK=false STRICT_EVENT=true # 严格要求每个页面都建立js文件 -STRICT_VIEW_JS=true \ No newline at end of file +STRICT_VIEW_JS=true + +UPDATE_LEVEL=production \ No newline at end of file diff --git a/app/common/command/admin/Update.php b/app/common/command/admin/Update.php index f163c15..2c6a0e0 100644 --- a/app/common/command/admin/Update.php +++ b/app/common/command/admin/Update.php @@ -8,10 +8,12 @@ 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\Output; use think\facade\App; +use think\facade\Env; class Update extends Command { @@ -39,25 +41,40 @@ class Update extends Command $version_file_regx = "/\bconst VERSION\s*=\s*'[\d\.a-z]+'/"; - $last_version_git = new Git(); $output->writeln('下载最新代码'); + $last_version_git = new Git(); + $last_version_repo = $last_version_git->cloneRepository(self::REPO, $last_version_dir); - $last_version_file = $last_version_dir . '/app/common/command/admin/Version.php'; - $last_version_str = file_get_contents($last_version_file); - preg_match($version_file_regx, $last_version_str, $matches); - $matched_version_str = $matches[0]; + $tags = $last_version_repo->getTags(); - $last_version = str_replace('const VERSION = ', '', $matched_version_str); - $last_version = str_replace('\'', '', $last_version); + $update_level = Env::get('adminsystem.update_level', 'production'); - // if ($last_version == $current_version) { - // $output->writeln('当前代码为最新版本,无需更新'); - // $this->cleanWorkpaceDir(); - // return; - // } + 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(); + + return; + } + + // 将最新代码切换到最新版本,因为最新的提交可能没有发布版本 + $output->writeln('切换最新代码的最新版本'); $last_version_repo->checkout($last_version); $current_version_git = new Git(); @@ -68,15 +85,66 @@ class Update extends Command // 获取当前版本需要跳过的文件 $current_version_update_config = include $current_version_dir . '/config/update.php'; - // 获取当前版本要替换的文件 + // 获取当前版本要替换的文件 $current_version_filesystem = new Filesystem(new LocalFilesystemAdapter($current_version_dir)); - $list_files = $current_version_filesystem->listContents('/', Filesystem::LIST_DEEP); - // dump($list_files); + $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(); + + $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; + + if (!PathTools::compareFiles($now_file_path, $current_version_file_path)) { + $changed_files[] = $file_path; + } + } + // 有定制修改则退出 + if (!empty($changed_files)) { + $output->warning('无法自动更新,以下文件被定制,请还原或手动升级:'); + + foreach ($changed_files as $file_path) { + $output->warning($file_path); + } + + return; + } + // 获取最新版本需要跳过的文件 // 获取最新版本要替换的文件 diff --git a/app/common/command/admin/Version.php b/app/common/command/admin/Version.php index 87ce6cf..2a8502e 100644 --- a/app/common/command/admin/Version.php +++ b/app/common/command/admin/Version.php @@ -14,7 +14,7 @@ use think\facade\App; class Version extends Command { - public const VERSION = 'v2.0.30-beta'; + public const VERSION = 'v2.0.30-dev'; public const LAYUI_VERSION = '2.8.16'; diff --git a/app/common/tools/PathTools.php b/app/common/tools/PathTools.php index 1d941c8..407c347 100644 --- a/app/common/tools/PathTools.php +++ b/app/common/tools/PathTools.php @@ -2,6 +2,7 @@ namespace app\common\tools; +use Diff; use think\facade\App; class PathTools @@ -103,4 +104,50 @@ class PathTools { return str_replace('/', '\\', $content); } + + public static function compareFiles($a, $b) + { + $text_mime_type = []; + $text_mime_type[] = 'text/html'; + $text_mime_type[] = 'text/plain'; + $text_mime_type[] = 'text/css'; + $text_mime_type[] = 'image/svg+xml'; + $text_mime_type[] = 'text/x-php'; + $text_mime_type[] = 'application/json'; + $text_mime_type[] = 'application/x-wine-extension-ini'; + + if (in_array(mime_content_type($a), $text_mime_type) && in_array(mime_content_type($b), $text_mime_type)) { + // 如果都是文本文件,则执行内容对比 + $diff = new Diff(file_get_contents($a), file_get_contents($b)); + $diff_content = $diff->getGroupedOpcodes(); + + if (!empty($diff_content)) { + return false; + } else { + return true; + } + } + + // Check if filesize is different + if (filesize($a) !== filesize($b)) { + return false; + } + + // Check if content is different + $ah = fopen($a, 'rb'); + $bh = fopen($b, 'rb'); + + $result = true; + while (!feof($ah)) { + if (fread($ah, 8192) != fread($bh, 8192)) { + $result = false; + break; + } + } + + fclose($ah); + fclose($bh); + + return $result; + } } diff --git a/composer.json b/composer.json index 84b200d..47dc92d 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "overtrue/flysystem-qiniu": "^3.0", "overtrue/flysystem-cos": "^5.0", "iidestiny/flysystem-oss": "^4.0", - "czproject/git-php": "^4.2" + "czproject/git-php": "^4.2", + "phpspec/php-diff": "^1.1" }, "require-dev": { "symfony/var-dumper": "^4.2" diff --git a/composer.lock b/composer.lock index 1fec4a5..715e82b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "431498e22ef6edab8343d1484636e6e0", + "content-hash": "484d22cf717f4d930f7542ec4c37bb17", "packages": [ { "name": "aliyuncs/oss-sdk-php", @@ -1508,6 +1508,47 @@ }, "time": "2023-06-14T22:48:31+00:00" }, + { + "name": "phpspec/php-diff", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/php-diff.git", + "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/php-diff/zipball/fc1156187f9f6c8395886fe85ed88a0a245d72e9", + "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9", + "shasum": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Diff": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Chris Boulton", + "homepage": "http://github.com/chrisboulton" + } + ], + "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "support": { + "source": "https://github.com/phpspec/php-diff/tree/v1.1.3" + }, + "time": "2020-09-18T13:47:07+00:00" + }, { "name": "psr/cache", "version": "3.0.0", diff --git a/config/update.php b/config/update.php index 372b8ba..5516aa7 100644 --- a/config/update.php +++ b/config/update.php @@ -4,16 +4,16 @@ $config = []; $skip_files = []; -$skip_files[] = '/app/common/app/functions.php'; -$skip_files[] = '/app/common/app/listen.php'; -$skip_files[] = '/app/common/app/middleware.php'; -$skip_files[] = '/app/common/app/service.php'; +$skip_files[] = 'app/common/app/functions.php'; +$skip_files[] = 'app/common/app/listen.php'; +$skip_files[] = 'app/common/app/middleware.php'; +$skip_files[] = 'app/common/app/service.php'; $config['skip_files'] = $skip_files; $skip_dir = []; -$skip_dir[] = '/runtime'; -$skip_dir[] = '/vendor'; +$skip_dir[] = 'runtime'; +$skip_dir[] = 'vendor'; $config['skip_dir'] = $skip_dir;