| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Python 环境列表更新脚本
- 功能:对比虚拟环境中已安装的包和 environment.txt,如果不一致则更新 environment.txt
- """
- import os
- import sys
- import subprocess
- import platform
- from pathlib import Path
- # 脚本所在目录即本环境目录,venv 固定为 env
- SCRIPT_DIR = Path(__file__).parent.absolute()
- _exe = Path(sys.executable).resolve()
- if "Scripts" in _exe.parts or "bin" in _exe.parts:
- VENV_PATH = _exe.parent.parent
- else:
- VENV_PATH = SCRIPT_DIR / "env"
- ENVIRONMENT_FILE = SCRIPT_DIR / "environment.txt"
- # 根据操作系统确定虚拟环境的 pip 路径
- if platform.system() == "Windows":
- VENV_PIP = VENV_PATH / "Scripts" / "pip.exe"
- else:
- VENV_PIP = VENV_PATH / "bin" / "pip"
- def run_command(cmd, check=True, capture_output=True):
- """运行命令并返回结果"""
- try:
- result = subprocess.run(
- cmd,
- shell=True,
- check=check,
- capture_output=capture_output,
- text=True,
- encoding='utf-8'
- )
- return result.returncode == 0, result.stdout, result.stderr
- except subprocess.CalledProcessError as e:
- return False, e.stdout if hasattr(e, 'stdout') else "", str(e)
- def get_installed_packages():
- """获取虚拟环境中已安装的包列表(使用 pip freeze)"""
- if not VENV_PATH.exists():
- print("[ERROR] Virtual environment not found")
- return None
-
- cmd = f'"{VENV_PIP}" freeze'
- success, output, error = run_command(cmd, check=False)
-
- if not success:
- print(f"[ERROR] Failed to get installed packages: {error}")
- return None
-
- # 解析输出,提取包名和版本
- packages = {}
- for line in output.strip().split('\n'):
- line = line.strip()
- if line and not line.startswith('#'):
- # 格式:package==version 或 package>=version 等
- if '==' in line:
- parts = line.split('==', 1)
- packages[parts[0].strip().lower()] = line.strip()
- else:
- # 如果没有版本号,使用整行
- pkg_name = line.split('>=')[0].split('<=')[0].split('>')[0].split('<')[0].split('~=')[0].strip()
- packages[pkg_name.lower()] = line.strip()
-
- return packages
- def read_environment_file():
- """读取 environment.txt 中的包列表"""
- if not ENVIRONMENT_FILE.exists():
- print(f"[WARN] {ENVIRONMENT_FILE} not found, will create new one")
- return {}
-
- packages = {}
- with open(ENVIRONMENT_FILE, 'r', encoding='utf-8') as f:
- for line in f:
- line = line.strip()
- if line and not line.startswith('#'):
- # 提取包名(支持各种版本操作符)
- if '==' in line:
- parts = line.split('==', 1)
- packages[parts[0].strip().lower()] = line.strip()
- else:
- pkg_name = line.split('>=')[0].split('<=')[0].split('>')[0].split('<')[0].split('~=')[0].strip()
- packages[pkg_name.lower()] = line.strip()
-
- return packages
- def compare_and_update():
- """对比并更新 environment.txt"""
- print("Comparing installed packages with environment.txt...")
- print("=" * 60)
-
- # 获取已安装的包
- installed_packages = get_installed_packages()
- if installed_packages is None:
- sys.exit(1)
-
- # 读取 environment.txt 中的包
- file_packages = read_environment_file()
-
- # 对比差异
- installed_set = set(installed_packages.keys())
- file_set = set(file_packages.keys())
-
- added_packages = installed_set - file_set
- removed_packages = file_set - installed_set
- changed_packages = []
-
- # 检查版本变化
- for pkg_name in installed_set & file_set:
- if installed_packages[pkg_name] != file_packages[pkg_name]:
- changed_packages.append(pkg_name)
-
- # 显示差异
- if added_packages:
- print(f"\n[+] Added packages ({len(added_packages)}):")
- for pkg in sorted(added_packages):
- print(f" + {installed_packages[pkg]}")
-
- if removed_packages:
- print(f"\n[-] Removed packages ({len(removed_packages)}):")
- for pkg in sorted(removed_packages):
- print(f" - {file_packages[pkg]}")
-
- if changed_packages:
- print(f"\n[~] Changed packages ({len(changed_packages)}):")
- for pkg in sorted(changed_packages):
- print(f" ~ {file_packages[pkg]} -> {installed_packages[pkg]}")
-
- # 判断是否需要更新
- if not added_packages and not removed_packages and not changed_packages:
- print("\n[OK] environment.txt is up to date")
- print(f" Total packages: {len(installed_packages)}")
- return True
-
- # 更新 environment.txt
- print(f"\nUpdating {ENVIRONMENT_FILE}...")
-
- # 使用 pip freeze 获取完整列表(包含所有依赖)
- cmd = f'"{VENV_PIP}" freeze'
- success, output, error = run_command(cmd, check=False)
-
- if not success:
- print(f"[ERROR] Failed to get installed packages: {error}")
- sys.exit(1)
-
- # 写入文件(使用 UTF-8 无 BOM 编码)
- with open(ENVIRONMENT_FILE, 'w', encoding='utf-8', newline='\n') as f:
- f.write(output)
-
- # 统计包数量
- package_count = len([line for line in output.strip().split('\n') if line.strip()])
-
- print(f"[OK] {ENVIRONMENT_FILE} updated successfully")
- print(f" Total packages: {package_count}")
-
- return True
- def main():
- """主函数"""
- if not compare_and_update():
- sys.exit(1)
- sys.exit(0)
- if __name__ == "__main__":
- main()
|