2025-12-07 18:04:42 +08:00
2026-01-31 13:11:44 +08:00
2025-12-07 18:19:45 +08:00
2025-12-08 21:44:44 +08:00
2026-02-01 22:10:55 +08:00

Spec Formatter

一个用 Rust 编写的高性能 RPM spec 文件格式化和规范化工具,支持按区域分别处理头部定义和脚本/文件区段。

功能特性

1. 智能格式化

  • 统一头部: 自动添加 SPDX 标准的文件头部(从现有文件提取贡献者信息或使用配置默认值)
  • 统一尾部: 自动添加标准的 %changelog 结尾,防止重复格式化时空行累积
  • 字段对齐:
    • 主要字段内容统一从第 16 列开始Name、Version、Release、License、URL、Source0、BuildRequires、Requires 等)
    • BuildOption 后固定 2 个空格
    • %package 行特殊间距规则(-n 参数 5 个空格)
    • %description 行特殊间距规则
  • 自动添加 RemoteAsset: 在 URL 和第一个 Source 之间自动插入 #!RemoteAsset 标记
  • %description 前空行: 确保每个 %description 前有一个空行
  • Tab 转换: 自动将 Tab 转换为 4 个空格

2. 区域化处理

  • 头部定义区(从开始到最后一个 %description 后):
    • 应用格式化规则
    • 对齐字段
    • 应用依赖替换
    • 拆分多依赖行BuildRequires
  • 脚本/文件区%prep、%build、%install、%files 等):
    • 保持原始格式,不进行对齐
    • 仅在 %files 区段应用路径替换

3. 字符串替换scope 支持)

  • dependencies(默认): 只在 BuildRequires/Requires 行生效
    • 包名替换(如 ninja-buildninja
    • devel 包转 pkgconfiglibxml2-develpkgconfig(libxml-2.0)
    • 正则表达式替换(如 qt6-qt*qt6-*
  • files: 只在 %files 区段生效
    • 路径变量替换(如 _qt6_headerdir_qt6_includedir
    • 确保不影响其他区域的宏变量
  • all: 全局替换(谨慎使用)
  • skip_lines: 支持条件跳过(如跳过 Provides: 行)

4. 行删除

  • 全局删除匹配的行(在区域分离前执行)
  • 支持正则表达式和字符串匹配
  • 常见用例:
    • 删除过时的 %ldconfig_scriptlets
    • 删除不规范的 Group: 字段

5. 固定替换

  • Release 行固定替换为 Release: %autorelease
  • 跳过已经是正确格式的行

6. 多依赖拆分

  • 自动将 BuildRequires 中多个空格分隔的包名拆分为多行
  • 智能处理版本比较符(>=、<=、==
  • 只处理 BuildRequires不拆分 Requires保留版本约束

安装

从源码编译

cd spec-formatter
cargo build --release
sudo cp target/release/spec-formatter /usr/local/bin/

安装配置文件

sudo mkdir -p /etc/spec-formatter
sudo cp config.yaml /etc/spec-formatter/

或者放到用户目录:

mkdir -p ~/.config/spec-formatter
cp config.yaml ~/.config/spec-formatter/

使用方法

基本用法

处理当前目录下的所有 .spec 文件:

spec-formatter

处理指定的文件或目录:

spec-formatter /path/to/file.spec
spec-formatter /path/to/specs/
spec-formatter *.spec

指定配置文件

spec-formatter --config ~/.config/spec-formatter/config.yaml file.spec
spec-formatter -c /path/to/custom-config.yaml *.spec

在 Git Hook 中使用

.git/hooks/pre-commit 中:

#!/bin/bash
spec-formatter --config ~/.config/spec-formatter/config.yaml $(git diff --cached --name-only --diff-filter=ACM | grep '\.spec$')

配置文件

配置文件搜索路径(按优先级):

  1. 命令行指定的 --config 路径(如果提供)
  2. 可执行文件所在目录的 spec-formatter.yamlconfig.yaml
  3. 当前工作目录的 spec-formatter.yamlconfig.yaml
  4. /etc/spec-formatter/config.yaml (系统配置)

配置示例

# 作者信息(用于 SPDX-FileContributor
contributor: "Your Name <your.email@example.com>"

# 字符串替换规则
replacements:
  # === 依赖包替换(默认 scope: dependencies只在 BuildRequires/Requires 行生效) ===
  - pattern: "ninja-build"
    replace: "ninja"
    skip_lines: []
    
  # 正则表达式替换
  - pattern: "qt6-qt([a-z]+)"
    replace: "qt6-$1"
    skip_lines: ["Provides:"]
    is_regex: true
  
  # devel 包转 pkgconfig
  - pattern: "libxml2-devel"
    replace: "pkgconfig(libxml-2.0)"
    skip_lines: []
    
  # === 文件路径替换scope: files只在 %files 区段生效) ===
  - pattern: "_qt6_headerdir"
    replace: "_qt6_includedir"
    scope: "files"
    skip_lines: []

# 删除规则(全局生效)
deletions:
  # 正则表达式删除(行首可选空格 + 可选% + ldconfig_scriptlets
  - pattern: "^\\s*%?ldconfig_scriptlets"
    is_regex: true
  
  # 字符串删除(行中包含即删除)
  - pattern: "Group:"
    is_regex: true

# 固定替换规则(完全替换整行)
fixed_replacements:
  - pattern: "^Release:.*$"
    replace: "Release:        %autorelease"
    is_regex: true

# 格式化配置
formatting:
  # 对齐基准字段
  align_base: "BuildSystem:"
  # 基准字段后的空格数
  base_spacing: 4
  # BuildOption 后的空格数
  build_option_spacing: 2
  
  # 需要对齐的字段(内容从第 16 列开始)
  align_fields:
    - "Name:"
    - "Version:"
    - "Release:"
    - "Summary:"
    - "License:"
    - "URL:"
    - "Source0:"
    - "BuildSystem:"
    - "BuildRequires:"
    - "Requires:"
    - "Provides:"
    - "BuildArch:"
    
  # Source/Patch 字段对齐
  source_patch_align: true

配置说明

替换规则replacements

  • pattern: 要匹配的字符串或正则表达式
  • replace: 替换后的字符串(支持正则捕获组,如 $1
  • scope: 作用范围
    • dependencies(默认):只在 BuildRequires/Requires 行生效
    • files:只在 %files 区段生效
    • all:全局生效(谨慎使用)
  • skip_lines: 跳过包含这些前缀的行
  • is_regex: 是否为正则表达式(默认 false

删除规则deletions

  • pattern: 匹配模式
  • is_regex:
    • true: 正则匹配整行
    • false: 字符串匹配(行中包含即删除)

输出示例

正在处理文件: example.spec
==================================================
原始行: BuildRequires:  ninja-build
修改为: BuildRequires:  ninja
---
原始行: BuildRequires:  libxml2-devel
修改为: BuildRequires:  pkgconfig(libxml-2.0)
---
删除行: %ldconfig_scriptlets
---
✓ 文件处理完成,共 3 处修改
==================================================

注意事项

  1. 备份重要文件: 工具会直接修改文件,建议在 Git 仓库中使用或先备份
  2. 配置文件语法: YAML 格式,注意缩进和特殊字符转义(如正则中的 \ 要写成 \\
  3. scope 设置:
    • 依赖替换默认不需要写 scope
    • 路径替换必须设置 scope: "files"
  4. 重复格式化: 工具设计为幂等的,多次运行结果一致(不会累积空行)
  5. %files 区段: 只替换路径变量,不进行格式化对齐,保持原始结构

开发

构建

cargo build
cargo run -- test.spec

测试

cargo test

许可证

MulanPSL-2.0

Description
No description provided
Readme 239 KiB
Languages
Rust 97%
Shell 3%