gibMacOS代码结构详解:核心模块与功能划分
一、项目概述
gibMacOS是一个能够直接从Apple服务器下载macOS组件的Python脚本工具,支持Python 2和Python 3环境。该工具通过解析Apple软件更新目录(SUCatalog)获取macOS安装程序信息,并提供交互式界面供用户选择和下载所需版本。项目采用模块化设计,将不同功能封装在独立模块中,实现了代码的高内聚低耦合。
二、整体架构
gibMacOS项目结构清晰,主要由核心执行脚本、功能模块和辅助脚本三部分组成:
核心文件说明
| 文件路径 | 功能描述 |
|---|---|
| gibMacOS.py | 主程序入口,负责解析命令行参数、协调各模块工作流程 |
| BuildmacOSInstallApp.py | 构建macOS安装应用程序,将下载的组件打包为可执行的.app文件 |
| Scripts/disk.py | 磁盘管理模块,提供磁盘信息查询和操作功能 |
| Scripts/downloader.py | 下载器模块,处理文件下载、进度显示和大小计算 |
| Scripts/plist.py | 属性列表(Property List)解析模块,处理Apple的plist格式文件 |
| Scripts/run.py | 系统命令执行模块,封装跨平台命令执行功能 |
| Scripts/utils.py | 通用工具函数模块,提供版本比较、用户交互等辅助功能 |
三、核心模块详解
3.1 gibMacOS主类(gibMacOS.py)
gibMacOS类是整个程序的核心控制器,负责协调各个模块完成主要工作流程。其主要功能包括:
主要工作流程如下:
关键方法解析:
build_url(): 构建Apple软件更新目录URL,根据当前选择的目录类型和macOS版本生成正确的URL:
def build_url(self, **kwargs):
catalog = kwargs.get("catalog", self.current_catalog).lower()
catalog = catalog if catalog.lower() in self.catalog_suffix else "publicrelease"
version = int(kwargs.get("version", self.current_macos))
return "https://swscan.apple.com/content/catalogs/others/index-{}.merged-1.sucatalog".format(
"-".join(reversed(self.get_macos_versions(self.min_macos,version,catalog=self.catalog_suffix.get(catalog,""))))
)
get_catalog_data(): 下载并解析Apple软件更新目录数据,支持本地缓存:
def get_catalog_data(self, local = False):
if local:
# 检查本地缓存
if os.path.exists(os.path.join(self.scripts, self.plist)):
# 尝试加载本地文件
try:
with open(os.path.join(self.scripts, self.plist), "rb") as f:
self.catalog_data = plist.load(f)
return True
except:
# 加载失败,转为下载
pass
# 下载远程目录
url = self.build_url(catalog=self.current_catalog, version=self.current_macos)
b = self.d.get_bytes(url, self.interactive)
self.catalog_data = plist.loads(b)
return True
3.2 下载器模块(downloader.py)
Downloader类负责处理所有网络下载任务,包括文件下载、进度显示和下载大小计算。其核心功能如下:
下载进度处理流程:
def _process_hook(queue, total_size, bytes_so_far=0, update_interval=1.0, max_packets=0):
"""处理下载进度更新的钩子函数"""
start = time.time()
last_update = 0
while True:
# 从队列获取最新下载进度
try:
data = queue.get(timeout=update_interval)
if data is None: # 下载完成
break
bytes_so_far += data
except:
pass
# 计算进度百分比和下载速度
percent = float(bytes_so_far) / total_size
elapsed = time.time() - start
rate = bytes_so_far / elapsed
# 更新显示进度条
if time.time() - last_update > update_interval or percent == 1.0:
last_update = time.time()
# 格式化进度信息并打印
# ...
3.3 属性列表解析模块(plist.py)
plist模块提供了对Apple属性列表(Property List)格式的解析和生成支持。该模块处理两种plist格式:XML格式和二进制格式。
核心功能:
关键函数:
| 函数名 | 功能描述 |
|---|---|
| readPlist(pathOrFile) | 读取plist文件,自动检测格式 |
| writePlist(value, pathOrFile) | 将Python对象写入plist文件 |
| loads(value) | 从字符串加载plist数据 |
| dumps(value) | 将Python对象序列化为plist格式字符串 |
二进制plist解析流程:
def load(fp, fmt=None, use_builtin_types=None, dict_type=dict):
"""加载plist文件,自动检测格式"""
if fmt is None:
# 检测文件格式
if _is_binary(fp):
fmt = FMT_BINARY
else:
# 尝试XML解析
# ...
if fmt == FMT_BINARY:
# 二进制plist解析器
p = _BinaryPlistParser(use_builtin_types=use_builtin_types, dict_type=dict_type)
return p.parse(fp)
else:
# XML格式解析
# ...
3.4 系统命令执行模块(run.py)
run模块封装了跨平台的系统命令执行功能,提供了统一的接口来执行外部命令并获取输出。
命令执行流程:
def run(self, command_list, leave_on_fail = False):
"""执行命令列表中的命令"""
if isinstance(command_list, dict):
command_list = [command_list]
for comm in command_list:
# 准备命令参数
args = comm.get("args", [])
shell = comm.get("shell", False)
sudo = comm.get("sudo", False)
# 如果需要管理员权限,添加sudo
if sudo and os.name != "nt" and not args[0] == "sudo":
args = ["sudo"] + args
# 执行命令并获取输出
try:
# 使用子进程执行命令
# ...
return (stdout, stderr, returncode)
except Exception as e:
# 处理异常
# ...
3.5 磁盘管理模块(disk.py/diskwin.py)
磁盘管理模块提供了跨平台的磁盘信息查询功能,在macOS和Windows系统上有不同的实现:
- disk.py: macOS系统的磁盘管理实现
- diskwin.py: Windows系统的磁盘管理实现
macOS磁盘信息获取流程:
核心磁盘信息查询函数:
def get_disk_info(self, disk):
"""获取指定磁盘的详细信息"""
for d in self.disks:
if d.get("DeviceIdentifier", "").endswith(disk):
return d
return None
def get_disk_fs(self, disk):
"""获取指定磁盘的文件系统信息"""
info = self.get_disk_info(disk)
if info:
return info.get("FilesystemName", "")
return None
def is_apfs(self, disk):
"""判断磁盘是否为APFS文件系统"""
fs_type = self.get_disk_fs_type(disk)
return fs_type.lower() == "apfs"
四、工作流程分析
4.1 完整下载流程
4.2 安装应用构建流程(BuildmacOSInstallApp.py)
BuildmacOSInstallApp.py负责将下载的组件构建为可执行的macOS安装应用:
关键修补InstallInfo.plist代码:
def main(self):
# ...前面代码省略...
print("Patching InstallInfo.plist...")
with open(os.path.join(shared_support,"InstallInfo.plist"),"rb") as f:
p = plist.load(f)
# 修改Payload Image Info部分,将InstallESDDmg.pkg替换为InstallESD.dmg
if "Payload Image Info" in p:
pii = p["Payload Image Info"]
if "URL" in pii:
pii["URL"] = pii["URL"].replace("InstallESDDmg.pkg","InstallESD.dmg")
if "id" in pii:
pii["id"] = pii["id"].replace("com.apple.pkg.InstallESDDmg","com.apple.dmg.InstallESD")
pii.pop("chunklistURL",None)
pii.pop("chunklistid",None)
# 保存修改后的plist
with open(os.path.join(shared_support,"InstallInfo.plist"),"wb") as f:
plist.dump(p,f)
五、扩展与定制
5.1 配置设置
gibMacOS支持通过settings.json文件进行配置,主要配置项包括:
{
"current_macos": 20,
"current_catalog": "publicrelease",
"print_urls": false,
"find_recovery": false,
"hide_pid": false
}
5.2 命令行参数
gibMacOS支持多种命令行参数以实现自动化操作:
| 参数 | 描述 |
|---|---|
| -l, --latest | 下载当前目录中最新版本 |
| -r, --recovery | 仅下载恢复分区更新 |
| -d, --dmg | 仅下载.dmg文件 |
| -c, --catalog | 指定要使用的目录类型 |
| -v, --version | 指定要下载的macOS版本 |
| -i, --print-urls | 仅打印下载URL,不实际下载 |
| -j, --print-json | 以JSON格式打印产品元数据 |
示例:下载最新版本的macOS
python gibMacOS.py --latest
示例:仅打印macOS Monterey的下载链接
python gibMacOS.py --version "Monterey" --print-urls
六、总结与扩展建议
6.1 项目优势
- 模块化设计:各功能清晰分离,便于维护和扩展
- 跨平台支持:支持macOS和Windows系统
- 灵活的配置:通过配置文件和命令行参数支持多种使用场景
- 完整的错误处理:各模块均有完善的异常处理机制
6.2 潜在改进方向
- 添加多线程下载:当前为单线程下载,可通过多线程提高下载速度
- 完善缓存机制:增加目录数据和组件文件的缓存策略
- GUI界面:开发图形用户界面,降低使用门槛
- 增量更新支持:实现组件的增量下载,减少重复下载
- 校验与修复:添加文件校验和损坏修复功能
6.3 典型应用场景
- 系统管理员:批量下载macOS安装介质
- 开发者:测试不同版本macOS兼容性
- 普通用户:创建可引导的macOS安装U盘
- 数据恢复:下载恢复分区组件进行系统修复
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



