Repository navigation
Expand file tree
/
Copy pathpersistence.py
More file actions
187 lines (154 loc) · 7.06 KB
/
Copy pathpersistence.py
File metadata and controls
187 lines (154 loc) · 7.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import os
import subprocess
import tempfile
import shutil
from datetime import datetime
import xml.etree.ElementTree as ET
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('persistence')
class GitRepository:
"""Git仓库操作类,用于克隆、拉取和推送RSS文件"""
def __init__(self):
"""初始化Git仓库操作类"""
self.repo_url = os.environ.get('GIT_REPO_URL')
self.username = os.environ.get('GIT_USERNAME')
self.email = os.environ.get('GIT_EMAIL')
self.token = os.environ.get('GIT_TOKEN')
if not all([self.repo_url, self.username, self.email, self.token]):
logger.warning("Git环境变量未完全设置,可能无法进行Git操作")
# 创建带认证的仓库URL
if self.repo_url and self.token and self.username:
# 替换https://协议为带token的URL
if self.repo_url.startswith('https://'):
self.auth_repo_url = self.repo_url.replace(
'https://',
f'https://{self.username}:{self.token}@'
)
else:
self.auth_repo_url = self.repo_url
else:
self.auth_repo_url = None
def _run_git_command(self, command, cwd=None):
"""运行Git命令"""
try:
result = subprocess.run(
command,
cwd=cwd,
check=True,
capture_output=True,
text=True
)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
logger.error(f"Git命令执行失败: {e.stderr}")
return None
def clone_repository(self, branch='main'):
"""克隆仓库到临时目录"""
if not self.auth_repo_url:
logger.error("未配置有效的Git仓库URL")
return None
# 创建临时目录
temp_dir = tempfile.mkdtemp(prefix="git_repo_")
logger.info(f"克隆仓库到临时目录: {temp_dir} (branch: {branch})")
# 克隆仓库 - try specific branch
cmd = ['git', 'clone', '-b', branch, self.auth_repo_url, temp_dir]
result = self._run_git_command(cmd)
# If branch specific clone fails, try default clone (maybe branch doesn't exist yet but will be created?)
# But for 'get_remote_search' we assume it exists. For push, we might want to create it.
# However, user says main/master mismatch. Let's start with strict branch mapping.
if result is None:
logger.warning(f"克隆分支 {branch} 失败,尝试默认克隆")
cmd = ['git', 'clone', self.auth_repo_url, temp_dir]
result = self._run_git_command(cmd)
if result is None:
logger.error("克隆仓库失败")
shutil.rmtree(temp_dir, ignore_errors=True)
return None
# 设置Git用户信息
self._run_git_command(['git', 'config', 'user.name', self.username], cwd=temp_dir)
self._run_git_command(['git', 'config', 'user.email', self.email], cwd=temp_dir)
return temp_dir
def push_feed_to_repository(self, feed_path):
"""将更新后的feed.xml推送到Git仓库"""
if not os.path.exists(feed_path):
logger.error(f"feed文件不存在: {feed_path}")
return False
# 克隆仓库 (Force main)
repo_dir = self.clone_repository(branch='main')
if not repo_dir:
return False
try:
# 复制feed.xml到仓库
repo_feed_path = os.path.join(repo_dir, 'feed.xml')
shutil.copy2(feed_path, repo_feed_path)
# 添加文件到Git
self._run_git_command(['git', 'add', 'feed.xml'], cwd=repo_dir)
# 提交更改
commit_message = f"更新RSS feed - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
commit_result = self._run_git_command(
['git', 'commit', '-m', commit_message],
cwd=repo_dir
)
if commit_result is None:
# nothing to commit possibly?
pass
# 推送到远程仓库 (Push current HEAD to main explicit)
# Increase buffer size to handle larger pushes if needed
self._run_git_command(['git', 'config', 'http.postBuffer', '524288000'], cwd=repo_dir)
push_result = self._run_git_command(
['git', 'push', 'origin', 'HEAD:main'],
cwd=repo_dir
)
success = push_result is not None
if success:
logger.info("成功推送feed.xml到Git仓库 (main)")
else:
logger.error("推送feed.xml到Git仓库失败 (main)")
return success
finally:
# 清理临时目录
shutil.rmtree(repo_dir, ignore_errors=True)
def get_remote_feed(self):
"""从远程仓库获取feed.xml文件"""
# 克隆仓库 (Force main)
repo_dir = self.clone_repository(branch='main')
if not repo_dir:
return None
try:
# 检查feed.xml是否存在
repo_feed_path = os.path.join(repo_dir, 'feed.xml')
if not os.path.exists(repo_feed_path):
logger.warning("远程仓库中不存在feed.xml文件")
return None
# 返回feed.xml的内容
with open(repo_feed_path, 'r', encoding='utf-8') as f:
content = f.read()
return content
finally:
# 清理临时目录
shutil.rmtree(repo_dir, ignore_errors=True)
def compare_feed_dates(local_feed_path, remote_feed_content):
"""比较本地和远程feed.xml的lastBuildDate,返回较新的那个"""
try:
# 解析本地feed.xml
local_tree = ET.parse(local_feed_path)
local_root = local_tree.getroot()
local_build_date = local_root.find('./channel/lastBuildDate').text
local_datetime = datetime.strptime(local_build_date, '%a, %d %b %Y %H:%M:%S %z')
# 解析远程feed.xml
remote_root = ET.fromstring(remote_feed_content)
remote_build_date = remote_root.find('./channel/lastBuildDate').text
remote_datetime = datetime.strptime(remote_build_date, '%a, %d %b %Y %H:%M:%S %z')
# 比较日期
if remote_datetime > local_datetime:
logger.info("远程feed.xml更新,使用远程版本")
return 'remote', remote_feed_content
else:
logger.info("本地feed.xml更新,使用本地版本")
return 'local', None
except Exception as e:
logger.error(f"比较feed日期时出错: {str(e)}")
logger.info("出错时默认使用本地feed.xml")
return 'local', None