#!/usr/bin/env python3 import importlib.metadata import re import os # 解析包的版本规范 def parse_package_spec(spec): """ 解析包名和版本规范。 返回 (name, operator, version)。 """ match = re.match(r'^([^=<>!~]+)\s*([=<>!~]+)\s*(.+)$', spec) if match: name, op, version = match.groups() return name.strip(), op.strip(), version.strip() else: return spec.strip(), None, None # 获取已安装包的版本 def get_installed_versions(packages): installed_versions = {} for pkg in packages: name, _, _ = parse_package_spec(pkg) try: installed_version = importlib.metadata.version(name) installed_versions[name] = installed_version except importlib.metadata.PackageNotFoundError: print(f"包 {name} 未安装。") continue return installed_versions # 读取现有的 requirements.txt def read_requirements(file_path='requirements.txt'): req_versions = {} if os.path.exists(file_path): with open(file_path, 'r') as f: for line in f: line = line.strip() if not line or line.startswith('#'): continue name, op, version_spec = parse_package_spec(line) if op and version_spec: req_versions[name] = f"{op}{version_spec}" else: req_versions[name] = None # 未指定版本 return req_versions # 合并包信息 def merge_requirements(installed_versions, req_versions): merged_requirements = [] conflict_detected = False processed_packages = set() for name, installed_version in installed_versions.items(): if name in req_versions: req_version_spec = req_versions[name] if req_version_spec: # 检查版本是否匹配 version_match = False # 支持多种版本操作符 ops = ['==', '>=', '<=', '>', '<', '!=', '~='] for op in ops: if req_version_spec.startswith(op): req_op = op req_ver = req_version_spec[len(op):] break else: req_op = None req_ver = None if req_op == '==': if req_ver == installed_version: merged_requirements.append(f"{name}=={installed_version}") else: # 版本冲突 merged_requirements.append(f"<<<<<<< HEAD") merged_requirements.append(f"{name}{req_version_spec}") merged_requirements.append(f"=======") merged_requirements.append(f"{name}=={installed_version}") merged_requirements.append(f">>>>>>> Merged version") conflict_detected = True else: # 如果 requirements.txt 中有版本规范但不是 '==' # 可以根据需要调整此逻辑 # 这里假设只在 '==' 时进行严格匹配 # 其他情况下认为没有冲突 merged_requirements.append(f"{name}{req_version_spec}") else: # requirements.txt 未指定版本,直接覆盖为已安装版本 merged_requirements.append(f"{name}=={installed_version}") processed_packages.add(name) else: # 包不在 requirements.txt 中,添加已安装版本 merged_requirements.append(f"{name}=={installed_version}") processed_packages.add(name) # 添加 requirements.txt 中未处理的包 for name, version_spec in req_versions.items(): if name not in processed_packages: if version_spec: merged_requirements.append(f"{name}{version_spec}") else: merged_requirements.append(f"{name}") return merged_requirements, conflict_detected def main(): # 读取现有的 requirements.txt 获取包列表 req_versions = read_requirements('requirements.txt') packages = list(req_versions.keys()) # 获取已安装包的版本 installed_versions = get_installed_versions(packages) # 合并包信息 merged_requirements, conflict_detected = merge_requirements(installed_versions, req_versions) # 将合并结果写回 requirements.txt with open('requirements.txt', 'w') as f: for line in merged_requirements: f.write(line + '\n') if conflict_detected: print("requirements.txt 已更新,存在版本冲突。请手动解决冲突标记。") else: print("requirements.txt 已更新,无版本冲突。") if __name__ == "__main__": main()