binary_repo.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """
  2. binary_repo.py - 管理二进制产物仓库。
  3. 对应原 Shell 中的 pull_binary_from_server / commit_binary_to_server。
  4. """
  5. import os
  6. import logging
  7. import subprocess
  8. from pathlib import Path
  9. from typing import List
  10. logger = logging.getLogger(__name__)
  11. class BinaryRepoError(Exception):
  12. """二进制仓库操作异常"""
  13. pass
  14. def pull_binaries(repo_dir: str) -> None:
  15. """
  16. 拉取二进制仓库到最新状态(相当于 git checkout 后清空工作区)。
  17. 对应原 Shell 的 pull_binary_from_server。
  18. Args:
  19. repo_dir: 本地仓库路径
  20. """
  21. path = Path(repo_dir)
  22. if not path.is_dir():
  23. logger.warning("Binary repo not found, skipping pull: %s", repo_dir)
  24. return
  25. # 切换到仓库目录
  26. original_cwd = os.getcwd()
  27. os.chdir(repo_dir)
  28. try:
  29. # 检查是否为有效的 git 仓库
  30. if not (path / '.git').is_dir():
  31. raise BinaryRepoError(f"Not a git repository: {repo_dir}")
  32. # 清理所有文件(包括隐藏文件,但保留 .git)
  33. _clean_worktree()
  34. # 恢复所有文件到 HEAD 状态
  35. subprocess.run(['git', 'checkout', '.'], check=True)
  36. logger.info("Binary repo synced: %s", repo_dir)
  37. except subprocess.CalledProcessError as e:
  38. raise BinaryRepoError(f"Failed to pull binary repo: {e}") from e
  39. finally:
  40. os.chdir(original_cwd)
  41. def commit_binaries(repo_dir: str, target_branch: str) -> None:
  42. """
  43. 自动提交二进制产物到远端分支。
  44. 对应原 Shell 的 commit_binary_to_server。
  45. Args:
  46. repo_dir: 本地仓库路径
  47. target_branch: 推送的目标分支
  48. """
  49. path = Path(repo_dir)
  50. if not path.is_dir():
  51. raise BinaryRepoError(f"Binary repo not found: {repo_dir}")
  52. original_cwd = os.getcwd()
  53. os.chdir(repo_dir)
  54. try:
  55. if not (path / '.git').is_dir():
  56. raise BinaryRepoError(f"Not a git repository: {repo_dir}")
  57. # git add 所有新增/修改文件
  58. subprocess.run(['git', 'add', '*'], check=True)
  59. # 尝试提交,如果 nothing to commit 则忽略错误
  60. try:
  61. subprocess.run(['git', 'commit', '-m', 'auto commit by server'],
  62. check=True, capture_output=True, text=True)
  63. except subprocess.CalledProcessError as e:
  64. if 'nothing to commit' in e.stderr.lower() or 'nothing added' in e.stderr.lower():
  65. logger.info("Nothing to commit in %s, skipping push", repo_dir)
  66. return
  67. else:
  68. raise
  69. # 推送到指定分支
  70. push_ref = f'HEAD:{target_branch}'
  71. subprocess.run(['git', 'push', 'origin', push_ref], check=True)
  72. logger.info("Binary repo pushed to %s: %s", target_branch, repo_dir)
  73. except subprocess.CalledProcessError as e:
  74. raise BinaryRepoError(f"Failed to commit/push binary repo: {e}") from e
  75. finally:
  76. os.chdir(original_cwd)
  77. def _clean_worktree() -> None:
  78. """
  79. 删除工作区所有文件(包括隐藏文件),但保持 .git 目录存在。
  80. """
  81. cwd = Path.cwd()
  82. for item in cwd.iterdir():
  83. if item.name == '.git':
  84. continue
  85. if item.is_dir():
  86. import shutil
  87. shutil.rmtree(item, ignore_errors=True)
  88. else:
  89. item.unlink(missing_ok=True)