def create_patch(dir_src, dir_all_release, create_patch_for_latest_n_version, dir_github_action_artifact, get_final_patch_path_only=False) -> str: latest_version = now_version path_bz = os.path.join(dir_src, "utils/bandizip_portable", "bz.exe") old_cwd = os.getcwd() os.chdir(dir_all_release) if not get_final_patch_path_only: logger.info(f"工作目录已调整为{os.getcwd()},最新版本为v{latest_version}") uploader = Uploader() if not get_final_patch_path_only: logger.info( f"尝试从网盘查找在{latest_version}版本之前最近{create_patch_for_latest_n_version}个版本的信息" ) old_version_infos = [] # type: List[HistoryVersionFileInfo] # 获取当前网盘的最新版本,若比当前发布版本低,也加入 netdisk_latest_version_fileinfo = uploader.find_latest_version() netdisk_latest_version = uploader.parse_version_from_djc_helper_file_name( netdisk_latest_version_fileinfo.name) if version_less(netdisk_latest_version, latest_version): old_version_infos.append( HistoryVersionFileInfo(netdisk_latest_version_fileinfo, netdisk_latest_version)) # 从历史版本网盘中查找旧版本 for page in range_from_one(100): folder_info = uploader.get_folder_info_by_url( uploader.folder_history_files.url, get_this_page=page) for file in folder_info.files: filename = file.name # type: str if not filename.startswith(uploader.history_version_prefix): # 跳过非历史版本的文件 continue file_version = uploader.parse_version_from_djc_helper_file_name( filename) info = HistoryVersionFileInfo(file, file_version) if not version_less(file_version, latest_version): continue if info in old_version_infos: # 已经加入过(可能重复) continue old_version_infos.append(info) if len(old_version_infos) >= create_patch_for_latest_n_version + 2: # 已经找到超过前n+2个版本,因为网盘返回的必定是按上传顺序排列的,不过为了保险起见,多考虑一些 break if create_patch_for_latest_n_version > len(old_version_infos): create_patch_for_latest_n_version = len(old_version_infos) old_version_infos = sorted( old_version_infos)[-create_patch_for_latest_n_version:] # 确认最终文件名 patch_oldest_version = old_version_infos[0].version patch_newest_version = old_version_infos[-1].version patches_dir = f"DNF蚊子腿小助手_增量更新文件_v{patch_oldest_version}_to_v{patch_newest_version}" temp_dir = "patches_temp" patch_7z_file = f"{patches_dir}.7z" if get_final_patch_path_only: return patch_7z_file logger.info(f"需要制作补丁包的版本为{old_version_infos}") # 确保版本都在本地 logger.info(f"确保以上版本均已下载并解压到本地~") for info in old_version_infos: local_folder_path = os.path.join(dir_all_release, f"DNF蚊子腿小助手_v{info.version}_by风之凌殇") local_7z_path = local_folder_path + ".7z" if os.path.isdir(local_folder_path): # 本地已存在对应版本,跳过 continue logger.info(f"本地发布目录不存在 {local_folder_path}") if not os.path.isfile(local_7z_path): logger.info(f"本地不存在{info.fileinfo.name}的7z文件,将从网盘下载") uploader.download_file(info.fileinfo, dir_all_release) logger.info(f"尝试解压 {info.fileinfo.name} 到 {local_folder_path}") decompress_dir_with_bandizip(local_7z_path, dir_src) # --------------------------- 实际只做补丁包 --------------------------- logger.info(color("bold_yellow") + f"将为【{old_version_infos}】版本制作补丁包") shutil.rmtree(patches_dir, ignore_errors=True) os.mkdir(patches_dir) shutil.rmtree(temp_dir, ignore_errors=True) os.mkdir(temp_dir) def temp_path(dir_name): return os.path.realpath(os.path.join(temp_dir, dir_name)) def preprocess_before_patch(temp_version_path): for filename in ["config.toml", "utils/auto_updater.exe"]: filepath = os.path.join(temp_version_path, filename) if os.path.isfile(filepath): os.remove(filepath) # 为旧版本创建patch文件 target_version_dir = f"DNF蚊子腿小助手_v{latest_version}_by风之凌殇" logger.info(f"目标版本目录为{target_version_dir}") shutil.copytree(target_version_dir, temp_path(target_version_dir)) preprocess_before_patch(temp_path(target_version_dir)) for idx, version_info in enumerate(old_version_infos): version = version_info.version patch_file = f"{patches_dir}/{version}.patch" logger.info("-" * 80) logger.info( color("bold_yellow") + f"[{idx + 1}/{len(old_version_infos)}] 创建从v{version}升级到v{latest_version}的补丁{patch_file}" ) version_dir = f"DNF蚊子腿小助手_v{version}_by风之凌殇" shutil.copytree(version_dir, temp_path(version_dir)) preprocess_before_patch(temp_path(version_dir)) subprocess.call([ os.path.realpath(os.path.join(dir_src, "utils/hdiffz.exe")), f"-p-{multiprocessing.cpu_count()}", # 设置系统最大cpu数 os.path.realpath(os.path.join(temp_dir, version_dir)), os.path.realpath(os.path.join(temp_dir, target_version_dir)), patch_file, ]) filesize = os.path.getsize(patch_file) logger.info(f"创建补丁{patch_file}结束,最终大小为{human_readable_size(filesize)}") # 移除临时目录 shutil.rmtree(temp_dir, ignore_errors=True) # 压缩打包 compress_dir_with_bandizip(patches_dir, patch_7z_file, dir_src) # 额外备份一份最新的供github action 使用 shutil.copyfile( patch_7z_file, os.path.join(dir_github_action_artifact, 'djc_helper_patches.7z')) os.chdir(old_cwd) return patch_7z_file
def package(dir_src, dir_all_release, release_dir_name, release_7z_name, dir_github_action_artifact): old_cwd = os.getcwd() show_head_line(f"开始打包 {release_dir_name} 所需内容", color("bold_yellow")) # 确保发布根目录存在 if not os.path.isdir(dir_all_release): os.mkdir(dir_all_release) # 并清空当前的发布版本目录 dir_current_release = os.path.realpath(os.path.join(dir_all_release, release_dir_name)) shutil.rmtree(dir_current_release, ignore_errors=True) os.mkdir(dir_current_release) logger.info(color("bold_yellow") + f"将部分内容从 {dir_src} 复制到 {dir_current_release} ") # 需要复制的文件与目录 files_to_copy = [] # 基于正则确定初始复制范围 reg_wantted_file = r'.*\.(toml|md|txt|png|jpg|docx|url)$' for file in os.listdir('.'): if not re.search(reg_wantted_file, file, flags=re.IGNORECASE): continue files_to_copy.append(file) # 额外补充一些文件和目录 files_to_copy.extend([ "config.example.toml", "DNF蚊子腿小助手.exe", "DNF蚊子腿小助手配置工具.exe", "DNF蚊子腿小助手配置文件.bat", "使用教程", "付费指引", "相关信息", "utils", ]) # 按顺序复制 files_to_copy = sorted(files_to_copy) # 复制文件与目录过去 for filename in files_to_copy: source = os.path.join(dir_src, filename) destination = os.path.join(dir_current_release, filename) if os.path.isdir(filename): logger.info(f"拷贝目录 {filename}") shutil.copytree(source, destination) else: logger.info(f"拷贝文件 {filename}") shutil.copyfile(source, destination) logger.info(color("bold_yellow") + "移动部分文件的位置和名称") files_to_move = [ ("utils/auto_updater.exe", "utils/auto_updater_latest.exe"), ("CHANGELOG.MD", "相关信息/CHANGELOG.MD"), ("README.MD", "相关信息/README.MD"), ] for src_file, dst_file in files_to_move: src_file = os.path.join(dir_current_release, src_file) dst_file = os.path.join(dir_current_release, dst_file) logger.info(f"移动{src_file}到{dst_file}") shutil.move(src_file, dst_file) logger.info(color("bold_yellow") + "清除一些无需发布的内容") dir_to_filenames_need_remove = { ".": [ *list(path.name for path in pathlib.Path(".").glob('requirements*.txt')), "config.toml.local", *list(path.name for path in pathlib.Path(".").glob('config.toml.github_action*')), ], "utils": [ "logs", ".db", ".cached", ".first_run", ".log.filename", "buy_auto_updater_users.txt", "user_monthly_pay_info.txt", "notices.txt", *list(path.name for path in pathlib.Path("utils").glob('chrome_portable_*')), "upx.exe", ], } for dir_path, filenames in dir_to_filenames_need_remove.items(): for filename in filenames: filepath = os.path.join(dir_current_release, f"{dir_path}/{filename}") if not os.path.exists(filepath): continue if os.path.isdir(filepath): logger.info(f"移除目录 {filepath}") shutil.rmtree(filepath, ignore_errors=True) else: logger.info(f"移除文件 {filepath}") os.remove(filepath) # 压缩打包 os.chdir(dir_all_release) logger.info(color("bold_yellow") + "开始压缩打包") compress_dir_with_bandizip(release_dir_name, release_7z_name, dir_src) # 额外备份一份最新的供github action 使用 shutil.copyfile(release_7z_name, os.path.join(dir_github_action_artifact, 'djc_helper.7z')) os.chdir(old_cwd)