Mac 系统依赖信息收集脚本模块化解析

Mac 系统依赖信息收集脚本模块化解析

该脚本核心功能是自动收集 macOS 系统中 Homebrew 安装包和 Python 第三方包的关键信息(名称、占用空间、功能描述),并整理生成结构化的 Excel 报告,整体采用模块化设计,各模块职责清晰、可复用性强,适配 macOS 环境的依赖管理场景。

一、脚本整体架构

脚本按 “功能职责” 拆分为工具函数模块Brew 依赖收集模块Python 包收集模块Excel 报告生成模块主程序入口模块五大核心模块,整体架构如下:

├── 工具函数模块:字节数格式化(通用能力)
├── Brew依赖收集模块:获取brew包名称/大小/描述
├── Python包收集模块:获取Python包名称/版本/大小/描述
├── Excel报告生成模块:数据写入Excel并格式化样式
└── 主程序入口模块:流程调度+依赖检查+异常处理

二、各模块功能与核心代码解析

模块 1:工具函数模块(通用能力封装)

核心职责:提供全局复用的工具函数,解决 “字节数转易读单位” 的通用需求,与业务逻辑解耦。

def get_human_readable_size(size_bytes):
    """将字节数转换为易读的单位(B/KB/MB/GB/TB),适配不同大小的依赖包展示"""
    if size_bytes == 0:
        return "0 B"
    size_names = ("B", "KB", "MB", "GB", "TB")
    # 按二进制位数计算单位层级(1024进制)
    i = int(len(bin(size_bytes)) // 10)
    p = 1024 ** i
    s = round(size_bytes / p, 2)
    return f"{s} {size_names[i]}"

关键说明

  • 适配 0 字节、大文件(GB 级)等边界场景,避免计算异常;
  • 采用 1024 进制(符合存储行业标准),保留 2 位小数,兼顾精度与可读性;
  • 函数无外部依赖,可直接复用至其他需要格式化文件大小的场景。

模块 2:Brew 依赖收集模块(系统包信息采集)

核心职责:针对 macOS 专属的 Homebrew 包管理器,采集已安装包的名称、磁盘占用大小、功能描述,是脚本的核心业务模块之一。

import subprocess
import json
import os
import shutil

def get_brew_packages_info():
    """获取brew安装的包信息:名称、大小、作用"""
    brew_packages = []

    # 前置检查:验证brew是否安装(避免无效执行)
    if not shutil.which("brew"):
        print("未检测到Homebrew,请先安装brew")
        return brew_packages

    try:
        # 步骤1:获取所有已安装的brew formula包名称
        list_result = subprocess.check_output(
            ["brew", "list", "--formula"],
            text=True,
            stderr=subprocess.DEVNULL  # 屏蔽错误输出,避免干扰
        ).splitlines()

        for pkg_name in list_result:
            pkg_name = pkg_name.strip()
            if not pkg_name:
                continue

            # 步骤2:通过brew info获取包的描述信息(JSON格式便于解析)
            info_result = subprocess.check_output(
                ["brew", "info", "--json=v1", pkg_name],
                text=True,
                stderr=subprocess.DEVNULL
            )
            pkg_info = json.loads(info_result)[0]
            pkg_desc = pkg_info.get("desc", "无描述信息")

            # 步骤3:遍历包的所有文件,计算总磁盘占用大小
            files_result = subprocess.check_output(
                ["brew", "ls", "--verbose", pkg_name],
                text=True,
                stderr=subprocess.DEVNULL
            ).splitlines()

            total_size = 0
            for file_path in files_result:
                file_path = file_path.strip()
                # 排除软链接,仅计算实际文件大小
                if os.path.exists(file_path) and not os.path.islink(file_path):
                    total_size += os.path.getsize(file_path)

            # 封装数据结构,统一格式
            brew_packages.append({
                "名称": pkg_name,
                "占用大小": get_human_readable_size(total_size),
                "作用": pkg_desc
            })

    except subprocess.CalledProcessError as e:
        print(f"获取brew包信息时出错: {e}")
    except Exception as e:
        print(f"处理brew包信息异常: {e}")

    return brew_packages

关键说明

  1. 前置校验:通过shutil.which("brew")检查 brew 是否安装,避免后续命令执行失败;
  2. 多命令协作
    • brew list --formula:获取已安装包列表(仅公式包,排除 cask);
    • brew info --json=v1:以 JSON 格式输出包信息,解析更稳定;
    • brew ls --verbose:列出包的所有安装文件,用于计算总大小;
  3. 精度保障:排除软链接(not os.path.islink),避免重复计算磁盘占用;
  4. 异常处理:捕获subprocess.CalledProcessError(命令执行失败)和通用异常,保证单个包解析失败不影响整体流程。

模块 3:Python 包收集模块(Python 依赖采集)

核心职责:采集当前 Python 环境中已安装包的名称(含版本)、磁盘占用大小、功能描述,适配不同 Python 环境(系统 Python / 虚拟环境)。

import pkg_resources
import sys
from pathlib import Path

def get_python_packages_info():
    """获取Python已安装包信息:名称、大小、作用"""
    python_packages = []

    try:
        # 步骤1:获取当前环境所有已安装的Python包
        installed_packages = pkg_resources.working_set

        for pkg in installed_packages:
            pkg_name = pkg.project_name
            pkg_version = pkg.version

            # 步骤2:定位包的安装路径,计算总大小
            # 兼容不同包的路径命名规则(小写/下划线替换横线)
            pkg_location = Path(pkg.location) / pkg_name.replace("-", "_").lower()
            if not pkg_location.exists():
                pkg_location = Path(pkg.location) / pkg_name

            total_size = 0
            if pkg_location.exists():
                if pkg_location.is_file():  # 单文件包(如egg-info)
                    total_size = pkg_location.stat().st_size
                else:  # 目录包,递归计算所有文件大小
                    for file in pkg_location.rglob("*"):
                        if file.is_file():
                            total_size += file.stat().st_size

            # 步骤3:通过pip show获取包的描述信息
            try:
                show_result = subprocess.check_output(
                    [sys.executable, "-m", "pip", "show", pkg_name],
                    text=True,
                    stderr=subprocess.DEVNULL
                )
                pkg_desc = "无描述信息"
                for line in show_result.splitlines():
                    if line.startswith("Description:"):
                        pkg_desc = line.split(":", 1)[1].strip()
                        break
            except:
                pkg_desc = "无法获取描述"

            # 封装数据,包含版本号提升信息完整性
            python_packages.append({
                "名称": f"{pkg_name} ({pkg_version})",
                "占用大小": get_human_readable_size(total_size),
                "作用": pkg_desc
            })

    except Exception as e:
        print(f"获取Python包信息异常: {e}")

    return python_packages

关键说明

  1. 环境适配:通过pkg_resources.working_set获取当前 Python 环境的包,适配虚拟环境 / 全局环境;
  2. 路径兼容:处理包名的 “横线 / 下划线”“大小写” 差异(如requests vs Requests),避免路径查找失败;
  3. 大小计算:区分单文件包和目录包,递归计算目录包的所有文件大小,保证精度;
  4. 描述获取:通过pip show命令获取描述,失败时默认 “无法获取描述”,不中断流程;
  5. 版本标注:包名称中包含版本号(如requests (2.31.0)),提升报告的实用性。

模块 4:Excel 报告生成模块(数据可视化输出)

核心职责:将采集到的 Brew/Python 包数据写入 Excel 文件,格式化单元格样式,提升报告可读性。

import openpyxl
from openpyxl.styles import Font, Alignment
import os

def write_to_excel(brew_data, python_data, output_file="mac_dependencies_report.xlsx"):
    """将数据写入Excel文件,分sheet展示Brew/Python依赖"""
    # 创建新工作簿
    wb = openpyxl.Workbook()

    # 删除默认的Sheet1,避免冗余
    wb.remove(wb.active)

    # 处理Brew数据:独立Sheet展示
    if brew_data:
        ws_brew = wb.create_sheet(title="Brew依赖")
        # 设置表头样式(加粗+居中)
        headers = ["名称", "占用大小", "作用"]
        for col, header in enumerate(headers, 1):
            cell = ws_brew.cell(row=1, column=col, value=header)
            cell.font = Font(bold=True)
            cell.alignment = Alignment(horizontal="center")

        # 写入数据行
        for row, pkg in enumerate(brew_data, 2):
            ws_brew.cell(row=row, column=1, value=pkg["名称"])
            ws_brew.cell(row=row, column=2, value=pkg["占用大小"])
            ws_brew.cell(row=row, column=3, value=pkg["作用"])

        # 调整列宽,适配内容展示
        ws_brew.column_dimensions["A"].width = 20
        ws_brew.column_dimensions["B"].width = 15
        ws_brew.column_dimensions["C"].width = 60

    # 处理Python数据:独立Sheet展示
    if python_data:
        ws_python = wb.create_sheet(title="Python包")
        # 表头样式与Brew Sheet保持一致
        headers = ["名称", "占用大小", "作用"]
        for col, header in enumerate(headers, 1):
            cell = ws_python.cell(row=1, column=col, value=header)
            cell.font = Font(bold=True)
            cell.alignment = Alignment(horizontal="center")

        # 写入数据行
        for row, pkg in enumerate(python_data, 2):
            ws_python.cell(row=row, column=1, value=pkg["名称"])
            ws_python.cell(row=row, column=2, value=pkg["占用大小"])
            ws_python.cell(row=row, column=3, value=pkg["作用"])

        # 调整列宽(Python包名含版本,需更宽)
        ws_python.column_dimensions["A"].width = 30
        ws_python.column_dimensions["B"].width = 15
        ws_python.column_dimensions["C"].width = 60

    # 保存文件并输出绝对路径,便于用户查找
    wb.save(output_file)
    print(f"报告已生成:{os.path.abspath(output_file)}")

关键说明

  1. 分 Sheet 设计:Brew 和 Python 数据分别放在不同 Sheet,结构清晰;
  2. 样式优化:表头加粗 + 居中,提升可读性;
  3. 列宽适配:根据内容特点调整列宽(如 “作用” 列 60 字符宽度,避免内容截断);
  4. 容错处理:仅当数据非空时创建对应 Sheet,避免生成空 Sheet;
  5. 路径提示:输出文件绝对路径,用户可直接复制打开。

模块 5:主程序入口模块(流程调度与依赖检查)

核心职责:作为脚本的入口,调度各模块执行流程,检查必要依赖,处理整体异常。

def main():
    """主函数:调度数据采集→报告生成全流程"""
    print("开始收集依赖信息...")

    # 步骤1:采集数据
    brew_info = get_brew_packages_info()
    python_info = get_python_packages_info()

    # 步骤2:生成Excel报告
    write_to_excel(brew_info, python_info)

    print("依赖信息收集完成!")


if __name__ == "__main__":
    # 前置检查:确保openpyxl已安装,未安装则自动安装
    try:
        import openpyxl
    except ImportError:
        print("正在安装必要依赖包...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", "openpyxl"])
        import openpyxl

    main()

关键说明

  1. 自动安装依赖:检测到openpyxl未安装时,自动通过pip安装,降低用户使用门槛;
  2. 流程简化:用户只需执行脚本,无需手动调用各模块,一键完成数据采集 + 报告生成;
  3. 用户反馈:输出执行进度提示(“开始收集”“完成”),提升使用体验;
  4. 入口防护:通过if __name__ == "__main__"保证模块导入时不执行主流程,提升脚本复用性。

三、脚本核心设计亮点

  1. 模块化解耦:各模块职责单一(如工具函数仅做格式化,采集模块仅做数据获取),便于单独修改 / 扩展(如新增 npm 包采集模块);
  2. 环境适配
    • 适配 macOS 的 Homebrew 环境,前置检查 brew 是否安装;
    • 适配不同 Python 环境,兼容包路径的命名差异;
  3. 容错性强
    • 单个包解析失败不影响整体流程;
    • 屏蔽子进程错误输出,避免干扰用户;
    • 自动安装缺失依赖,降低使用门槛;
  4. 用户友好
    • 易读的大小格式、结构化的 Excel 报告;
    • 清晰的进度提示、绝对路径输出;
    • 样式化的 Excel 单元格,提升报告可读性;
  5. 可复用性:各模块可单独导入使用(如get_human_readable_size函数可复用至其他脚本,get_python_packages_info可单独采集 Python 包信息)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值