-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate_script.py
More file actions
327 lines (279 loc) · 12.2 KB
/
Copy pathupdate_script.py
File metadata and controls
327 lines (279 loc) · 12.2 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/usr/bin/env python3
"""
KCTube Update Script
Tự động cập nhật KCTube từ Git repository
"""
import os
import sys
import subprocess
import json
import shutil
import time
from datetime import datetime
class KCTubeUpdater:
def __init__(self):
self.backup_dir = f"backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
self.config_file = "app_config.json"
self.cache_file = "video_cache.json"
def log(self, message, level="INFO"):
"""Log message với timestamp"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {level}: {message}")
def run_command(self, command, capture_output=True, timeout=300):
"""Chạy command và trả về kết quả"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=capture_output,
text=True,
timeout=timeout
)
return result
except subprocess.TimeoutExpired:
self.log(f"Command timed out: {command}", "ERROR")
return None
except Exception as e:
self.log(f"Command failed: {command} - {str(e)}", "ERROR")
return None
def check_git_repository(self):
"""Kiểm tra xem có phải là git repository không"""
self.log("Kiểm tra Git repository...")
result = self.run_command("git status")
if result and result.returncode == 0:
self.log("✓ Đây là Git repository hợp lệ")
return True
else:
self.log("✗ Không phải Git repository hoặc có lỗi", "ERROR")
return False
def create_backup(self):
"""Tạo backup cho các file quan trọng"""
self.log("Tạo backup...")
try:
os.makedirs(self.backup_dir, exist_ok=True)
# Backup config file
if os.path.exists(self.config_file):
shutil.copy2(self.config_file, os.path.join(self.backup_dir, self.config_file))
self.log(f"✓ Đã backup {self.config_file}")
# Backup cache file
if os.path.exists(self.cache_file):
shutil.copy2(self.cache_file, os.path.join(self.backup_dir, self.cache_file))
self.log(f"✓ Đã backup {self.cache_file}")
# Backup requirements.txt
if os.path.exists("requirements.txt"):
shutil.copy2("requirements.txt", os.path.join(self.backup_dir, "requirements.txt"))
self.log("✓ Đã backup requirements.txt")
self.log(f"✓ Backup hoàn tất tại: {self.backup_dir}")
return True
except Exception as e:
self.log(f"✗ Lỗi khi tạo backup: {str(e)}", "ERROR")
return False
def check_git_status(self):
"""Kiểm tra trạng thái Git"""
self.log("Kiểm tra trạng thái Git...")
# Kiểm tra branch hiện tại
result = self.run_command("git branch --show-current")
if result and result.returncode == 0:
current_branch = result.stdout.strip()
self.log(f"Branch hiện tại: {current_branch}")
else:
self.log("Không thể xác định branch hiện tại", "WARNING")
current_branch = "main"
# Kiểm tra thay đổi local
result = self.run_command("git status --porcelain")
if result and result.stdout.strip():
self.log("Có thay đổi local, sẽ stash...")
return True, current_branch
else:
self.log("Không có thay đổi local")
return False, current_branch
def stash_changes(self):
"""Stash thay đổi local"""
self.log("Stash thay đổi local...")
result = self.run_command("git stash")
if result and result.returncode == 0:
self.log("✓ Đã stash thay đổi local")
return True
else:
self.log("✗ Lỗi khi stash thay đổi", "ERROR")
return False
def fetch_updates(self):
"""Fetch cập nhật từ remote"""
self.log("Fetch cập nhật từ remote...")
result = self.run_command("git fetch origin")
if result and result.returncode == 0:
self.log("✓ Đã fetch cập nhật")
return True
else:
self.log("✗ Lỗi khi fetch cập nhật", "ERROR")
return False
def check_updates_available(self, branch="main"):
"""Kiểm tra có cập nhật mới không"""
self.log("Kiểm tra cập nhật mới...")
result = self.run_command(f"git rev-list HEAD..origin/{branch} --count")
if result and result.returncode == 0:
commits_behind = int(result.stdout.strip())
if commits_behind > 0:
self.log(f"✓ Có {commits_behind} commit cần cập nhật")
return True, commits_behind
else:
self.log("✓ Đã là phiên bản mới nhất")
return False, 0
else:
self.log("✗ Không thể kiểm tra cập nhật", "ERROR")
return False, 0
def pull_updates(self, branch="main"):
"""Pull cập nhật mới"""
self.log(f"Pull cập nhật từ origin/{branch}...")
result = self.run_command(f"git pull origin {branch}")
if result and result.returncode == 0:
self.log("✓ Đã pull cập nhật thành công")
return True
else:
self.log("✗ Lỗi khi pull cập nhật", "ERROR")
return False
def check_requirements_changed(self):
"""Kiểm tra requirements.txt có thay đổi không"""
self.log("Kiểm tra thay đổi requirements.txt...")
result = self.run_command("git diff HEAD~1 HEAD --name-only")
if result and result.returncode == 0 and "requirements.txt" in result.stdout:
self.log("✓ requirements.txt đã thay đổi")
return True
else:
self.log("requirements.txt không thay đổi")
return False
def update_dependencies(self):
"""Cập nhật dependencies"""
self.log("Cập nhật dependencies...")
result = self.run_command("pip install -r requirements.txt")
if result and result.returncode == 0:
self.log("✓ Đã cập nhật dependencies")
return True
else:
self.log("✗ Lỗi khi cập nhật dependencies", "ERROR")
return False
def update_yt_dlp(self):
"""Cập nhật yt-dlp"""
self.log("Cập nhật yt-dlp...")
result = self.run_command("pip install -U yt-dlp")
if result and result.returncode == 0:
self.log("✓ Đã cập nhật yt-dlp")
return True
else:
self.log("✗ Lỗi khi cập nhật yt-dlp", "ERROR")
return False
def get_current_commit(self):
"""Lấy thông tin commit hiện tại"""
result = self.run_command('git log -1 --pretty=format:"%h - %s (%cr)"')
if result and result.returncode == 0:
return result.stdout.strip()
return "Unknown"
def restore_stash(self):
"""Khôi phục stash"""
self.log("Khôi phục stash...")
result = self.run_command("git stash pop")
if result and result.returncode == 0:
self.log("✓ Đã khôi phục stash")
return True
else:
self.log("✗ Lỗi khi khôi phục stash", "ERROR")
return False
def run_update(self):
"""Chạy toàn bộ quá trình update"""
self.log("=== BẮT ĐẦU QUÁ TRÌNH CẬP NHẬT KCTube ===")
# Bước 1: Kiểm tra Git repository
if not self.check_git_repository():
return False
# Bước 2: Tạo backup
if not self.create_backup():
self.log("Tiếp tục mà không có backup...", "WARNING")
# Bước 3: Kiểm tra trạng thái Git
has_changes, current_branch = self.check_git_status()
# Bước 4: Stash thay đổi nếu có
if has_changes:
if not self.stash_changes():
return False
# Bước 5: Fetch cập nhật
if not self.fetch_updates():
return False
# Bước 6: Kiểm tra có cập nhật mới không
has_updates, commits_behind = self.check_updates_available(current_branch)
if not has_updates:
self.log("Không có cập nhật mới")
return True
# Bước 7: Pull cập nhật
if not self.pull_updates(current_branch):
return False
# Bước 8: Kiểm tra và cập nhật dependencies
if self.check_requirements_changed():
if not self.update_dependencies():
self.log("Cảnh báo: Không thể cập nhật dependencies", "WARNING")
# Bước 9: Cập nhật yt-dlp
if not self.update_yt_dlp():
self.log("Cảnh báo: Không thể cập nhật yt-dlp", "WARNING")
# Bước 10: Khôi phục stash nếu có
if has_changes:
self.restore_stash()
# Bước 11: Hiển thị kết quả
current_commit = self.get_current_commit()
self.log(f"=== CẬP NHẬT HOÀN TẤT ===")
self.log(f"Commit hiện tại: {current_commit}")
self.log(f"Số commit đã cập nhật: {commits_behind}")
self.log(f"Backup được lưu tại: {self.backup_dir}")
self.log("Vui lòng khởi động lại ứng dụng để áp dụng thay đổi")
return True
def rollback(self):
"""Rollback về trạng thái trước khi update"""
self.log("=== ROLLBACK ===")
# Khôi phục từ backup
if os.path.exists(self.backup_dir):
try:
# Khôi phục config
backup_config = os.path.join(self.backup_dir, self.config_file)
if os.path.exists(backup_config):
shutil.copy2(backup_config, self.config_file)
self.log(f"✓ Đã khôi phục {self.config_file}")
# Khôi phục cache
backup_cache = os.path.join(self.backup_dir, self.cache_file)
if os.path.exists(backup_cache):
shutil.copy2(backup_cache, self.cache_file)
self.log(f"✓ Đã khôi phục {self.cache_file}")
self.log("✓ Rollback hoàn tất")
return True
except Exception as e:
self.log(f"✗ Lỗi khi rollback: {str(e)}", "ERROR")
return False
else:
self.log("✗ Không tìm thấy backup", "ERROR")
return False
def main():
"""Main function"""
updater = KCTubeUpdater()
if len(sys.argv) > 1:
if sys.argv[1] == "--rollback":
success = updater.rollback()
elif sys.argv[1] == "--help":
print("""
KCTube Update Script
Usage:
python update_script.py # Cập nhật bình thường
python update_script.py --rollback # Rollback về trạng thái trước
python update_script.py --help # Hiển thị help
Options:
--rollback Rollback về trạng thái trước khi update
--help Hiển thị thông tin này
""")
return
else:
print("Option không hợp lệ. Sử dụng --help để xem hướng dẫn.")
return
else:
success = updater.run_update()
if success:
print("\n✅ Cập nhật thành công!")
sys.exit(0)
else:
print("\n❌ Cập nhật thất bại!")
sys.exit(1)
if __name__ == "__main__":
main()