-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_gui.bat
More file actions
398 lines (328 loc) · 13.3 KB
/
build_gui.bat
File metadata and controls
398 lines (328 loc) · 13.3 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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#!/usr/bin/env python3
"""
GitGuard Sync 跨平台自動打包腳本
支援 Windows、macOS、Linux 三大平台
"""
import os
import sys
import shutil
import subprocess
import platform
from pathlib import Path
class GitGuardSyncBuilder:
"""GitGuard Sync 建置工具"""
def __init__(self):
self.app_name = "GitGuard-Sync"
self.script_name = "gitguard_sync.py"
self.version = "3.0.0"
self.dist_dir = "release"
self.build_dir = "build"
self.platform = platform.system().lower()
# 平台特定設定
self.platform_config = {
'windows': {
'executable_suffix': '.exe',
'separator': ';',
'icon_param': '--icon=icon.ico' if Path('icon.ico').exists() else ''
},
'darwin': { # macOS
'executable_suffix': '',
'separator': ':',
'icon_param': '--icon=icon.icns' if Path('icon.icns').exists() else ''
},
'linux': {
'executable_suffix': '',
'separator': ':',
'icon_param': ''
}
}
def print_banner(self):
"""顯示標題橫幅"""
banner = """
╔══════════════════════════════════════════════════════════════════════════════╗
║ GitGuard Sync 自動建置工具 ║
║ Git 倉庫安全同步守護者 - v3.0.0 ║
╚══════════════════════════════════════════════════════════════════════════════╝
"""
print(banner)
print(f"🖥️ 目標平台: {platform.system()} {platform.machine()}")
print(f"🐍 Python 版本: {sys.version.split()[0]}")
print()
def check_environment(self):
"""檢查建置環境"""
print("[1/7] 檢查建置環境...")
# 檢查 Python 版本
if sys.version_info < (3, 7):
print("❌ 錯誤: Python 版本過低,需要 3.7 或更高版本")
return False
# 檢查主程式檔案
if not Path(self.script_name).exists():
print(f"❌ 錯誤: 找不到主程式檔案 {self.script_name}")
return False
print("✅ 環境檢查通過")
return True
def install_dependencies(self):
"""安裝建置依賴"""
print("\n[2/7] 安裝建置依賴...")
try:
# 升級 pip
subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'],
check=True, capture_output=True)
# 安裝 PyInstaller
subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pyinstaller'],
check=True, capture_output=True)
# 安裝專案依賴
dependencies = ['gitpython', 'requests']
subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade'] + dependencies,
check=True, capture_output=True)
print("✅ 依賴套件安裝完成")
return True
except subprocess.CalledProcessError as e:
print(f"❌ 安裝依賴失敗: {e}")
return False
def clean_old_builds(self):
"""清理舊建置檔案"""
print("\n[3/7] 清理舊建置檔案...")
try:
# 移除舊目錄
for directory in [self.dist_dir, self.build_dir]:
if Path(directory).exists():
shutil.rmtree(directory)
# 移除 spec 檔案
for spec_file in Path('.').glob('*.spec'):
spec_file.unlink()
print("✅ 舊檔案清理完成")
return True
except Exception as e:
print(f"❌ 清理失敗: {e}")
return False
def create_version_file(self):
"""創建版本資訊檔案(Windows 專用)"""
if self.platform != 'windows':
return True
print("\n[4/7] 創建版本資訊檔案...")
version_info = f"""# UTF-8
VSVersionInfo(
ffi=FixedFileInfo(
filevers=({self.version.replace('.', ',')},0),
prodvers=({self.version.replace('.', ',')},0),
mask=0x3f,
flags=0x0,
OS=0x40004,
fileType=0x1,
subtype=0x0,
date=(0, 0)
),
kids=[
StringFileInfo(
[
StringTable(
u'040904B0',
[StringStruct(u'CompanyName', u''),
StringStruct(u'FileDescription', u'GitGuard Sync - Git 倉庫安全同步守護者'),
StringStruct(u'FileVersion', u'{self.version}'),
StringStruct(u'InternalName', u'{self.app_name}'),
StringStruct(u'LegalCopyright', u'MIT License'),
StringStruct(u'OriginalFilename', u'{self.app_name}.exe'),
StringStruct(u'ProductName', u'GitGuard Sync'),
StringStruct(u'ProductVersion', u'{self.version}')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)
"""
try:
with open('version_info.py', 'w', encoding='utf-8') as f:
f.write(version_info)
print("✅ 版本資訊檔案創建完成")
return True
except Exception as e:
print(f"❌ 創建版本資訊檔案失敗: {e}")
return False
def build_executable(self):
"""建置執行檔"""
print("\n[5/7] 開始建置執行檔...")
config = self.platform_config.get(self.platform, self.platform_config['linux'])
# 基本參數
cmd = [
'pyinstaller',
'--onefile',
'--name', self.app_name,
'--distpath', self.dist_dir,
'--workpath', self.build_dir,
'--clean',
'--noconfirm'
]
# 平台特定參數
if self.platform == 'windows':
cmd.append('--windowed') # Windows 隱藏控制台
if config['icon_param']:
cmd.extend(['--icon', 'icon.ico'])
if Path('version_info.py').exists():
cmd.extend(['--version-file', 'version_info.py'])
elif self.platform == 'darwin': # macOS
if config['icon_param']:
cmd.extend(['--icon', 'icon.icns'])
cmd.append('--windowed')
# 隱藏匯入模組
hidden_imports = [
'tkinter', 'tkinter.ttk', 'tkinter.font',
'tkinter.filedialog', 'tkinter.messagebox', 'tkinter.scrolledtext',
'git', 'git.repo', 'git.remote',
'requests', 'threading', 'subprocess',
'pathlib', 'json', 're', 'webbrowser',
'datetime', 'dataclasses', 'typing'
]
for module in hidden_imports:
cmd.extend(['--hidden-import', module])
# 排除不需要的大型模組
exclude_modules = ['matplotlib', 'numpy', 'pandas', 'scipy']
for module in exclude_modules:
cmd.extend(['--exclude-module', module])
# 主程式檔案
cmd.append(self.script_name)
print(f"📦 建置命令: {' '.join(cmd)}")
print("🔧 正在建置,請稍候...")
try:
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("✅ 建置完成")
return True
except subprocess.CalledProcessError as e:
print(f"❌ 建置失敗: {e}")
if e.stdout:
print(f"標準輸出: {e.stdout}")
if e.stderr:
print(f"錯誤輸出: {e.stderr}")
return False
def verify_build(self):
"""驗證建置結果"""
print("\n[6/7] 驗證建置結果...")
config = self.platform_config.get(self.platform, self.platform_config['linux'])
executable_name = f"{self.app_name}{config['executable_suffix']}"
executable_path = Path(self.dist_dir) / executable_name
if executable_path.exists():
# 獲取檔案大小
file_size = executable_path.stat().st_size
size_mb = file_size / (1024 * 1024)
print("✅ 建置驗證成功")
print(f"📊 執行檔資訊:")
print(f" 📁 檔案路徑: {executable_path}")
print(f" 📏 檔案大小: {size_mb:.1f} MB")
print(f" 🏗️ 建置平台: {platform.system()} {platform.machine()}")
return True
else:
print(f"❌ 建置驗證失敗: 找不到執行檔 {executable_path}")
return False
def cleanup_and_finalize(self):
"""清理和最終處理"""
print("\n[7/7] 最終處理...")
try:
# 詢問是否保留建置快取
keep_cache = input("是否保留建置快取?(y/N): ").lower().startswith('y')
if not keep_cache:
# 清理建置快取
if Path(self.build_dir).exists():
shutil.rmtree(self.build_dir)
# 清理 spec 檔案
for spec_file in Path('.').glob('*.spec'):
spec_file.unlink()
# 清理版本資訊檔案
if Path('version_info.py').exists():
Path('version_info.py').unlink()
print("🗑️ 建置快取已清理")
# 創建使用說明
self.create_usage_instructions()
print("✅ 最終處理完成")
return True
except Exception as e:
print(f"❌ 最終處理失敗: {e}")
return False
def create_usage_instructions(self):
"""創建使用說明檔案"""
config = self.platform_config.get(self.platform, self.platform_config['linux'])
executable_name = f"{self.app_name}{config['executable_suffix']}"
instructions = f"""GitGuard Sync v{self.version} 使用說明
{'=' * 50}
📦 建置資訊:
- 建置平台: {platform.system()} {platform.machine()}
- 建置時間: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- Python 版本: {sys.version.split()[0]}
🚀 執行方式:
"""
if self.platform == 'windows':
instructions += f"""
1. 雙擊執行 {executable_name}
2. 或在命令提示字元中執行:
{executable_name}
"""
else:
instructions += f"""
1. 在終端機中執行:
./{executable_name}
2. 如果遇到權限問題,請先執行:
chmod +x {executable_name}
"""
instructions += f"""
📋 系統需求:
- 作業系統: {platform.system()}
- 記憶體: 至少 100MB 可用
- 硬碟空間: 50MB
🔧 功能特色:
- Git 倉庫安全掃描
- 雙平台同步 (GitHub + GitLab)
- GitGuardian API 整合
- 現代化 GUI 介面
📞 技術支援:
- 專案網頁: https://github.com/seikaikyo/gitguard-sync
⚠️ 注意事項:
- 首次執行可能需要較長時間載入
- 防毒軟體可能會誤報,請加入白名單
- 使用 GitGuardian 功能需要 API 金鑰
🎉 感謝使用 GitGuard Sync!
"""
try:
readme_path = Path(self.dist_dir) / 'README.txt'
with open(readme_path, 'w', encoding='utf-8') as f:
f.write(instructions)
print(f"📝 使用說明已創建: {readme_path}")
except Exception as e:
print(f"⚠️ 創建使用說明失敗: {e}")
def run(self):
"""執行完整建置流程"""
self.print_banner()
steps = [
self.check_environment,
self.install_dependencies,
self.clean_old_builds,
self.create_version_file,
self.build_executable,
self.verify_build,
self.cleanup_and_finalize
]
for step in steps:
if not step():
print(f"\n❌ 建置過程失敗,請檢查上方錯誤訊息")
return False
print(f"\n🎉 GitGuard Sync v{self.version} 建置完成!")
print(f"📦 執行檔位置: {Path(self.dist_dir).absolute()}")
# 詢問是否開啟輸出目錄
if input("\n是否要開啟輸出目錄?(Y/n): ").lower() != 'n':
try:
if self.platform == 'windows':
os.startfile(self.dist_dir)
elif self.platform == 'darwin':
subprocess.run(['open', self.dist_dir])
else: # linux
subprocess.run(['xdg-open', self.dist_dir])
except Exception as e:
print(f"⚠️ 無法開啟目錄: {e}")
return True
def main():
"""主函式"""
builder = GitGuardSyncBuilder()
success = builder.run()
if not success:
input("\n按 Enter 鍵離開...")
sys.exit(1)
if __name__ == "__main__":
main()