rpm-spec-tool 0.1.1

Pretty-printer and static analyzer CLI for RPM .spec files
rpm-spec-tool-0.1.1 is not a library.

rpm-spec-tool

CI Crates.io docs.rs MSRV dependency status License

Pretty-printer and static analyzer CLI for RPM .spec files.

Built on top of the rpm-spec parser and a visitor-based analyzer that ships with 24 built-in distribution profiles (generic, RHEL 8/9/10, Fedora-derived families, SUSE, ALT Linux variants).

Features

  • Static analysis — lint rules over the parsed AST with rich codespan-style diagnostics. Output as human-readable text, JSON, or SARIF for GitHub Code Scanning.
  • Auto-fixeslint --fix applies machine-applicable rewrites in place; --fix-suggested also commits "maybe-incorrect" rewrites.
  • Severity overrides--deny, --warn, --allow on the CLI; per-lint defaults in .rpmspec.toml.
  • Pretty-printerformat for canonical reformat (with --check, --in-place, --diff modes for CI / pre-commit); pretty streams the reformatted text to stdout with ANSI syntax highlighting.
  • Distribution profiles — 24 built-in profiles select the right macro registry, rpmlib feature set, and family-gated lints. Pick one with --profile <name> or via .rpmspec.toml.
  • --define like rpmbuild-D 'NAME VALUE' injects macros at lint time; CLI defines outrank profile / config defaults. Repeatable.
  • Shellcheck integration — optional. The analyzer invokes shellcheck on %prep, %build, %install script sections and surfaces its findings; missing shellcheck in $PATH is reported as a separate diagnostic, never crashes the lint. Configurable via [shellcheck] in .rpmspec.toml.
  • AST dumpast emits the parsed AST as JSON or YAML for downstream tooling.

Quick start

# Lint, with a chosen distribution profile:
rpm-spec-tool lint --profile rhel-9-x86_64 my-package.spec

# Apply auto-fixes, then reformat in place:
rpm-spec-tool lint   --fix --profile rhel-9-x86_64 my-package.spec
rpm-spec-tool format --in-place                    my-package.spec

# CI: one-shot lint + format check (exits non-zero on any issue):
rpm-spec-tool check --profile rhel-9-x86_64 my-package.spec

# SARIF output for GitHub Code Scanning:
rpm-spec-tool lint --format sarif my-package.spec > spec.sarif

# Inspect a built-in profile:
rpm-spec-tool profile show rhel-9-x86_64
rpm-spec-tool profile list

# Compare a macro across profiles (note: macro name without `%`):
rpm-spec-tool profile macro dist rhel-9-x86_64 rhel-10-x86_64

Every spec-taking subcommand reads from stdin when the path is - or omitted.

Configuration

Drop a .rpmspec.toml next to your specs (or anywhere up the directory tree — the tool walks upward from each input). Minimal example:

# Pick the active distribution profile. CLI `--profile` overrides this.
profile = "rhel-9-x86_64"

# Per-lint severity overrides. CLI flags --deny/--warn/--allow win.
# Rule IDs below are illustrative — see the lint reference for the full list.
[lints]
RPM031 = "warn"
RPM093 = "allow"

# Tune shellcheck. Set `shellcheck = "allow"` at the top level to
# disable shellcheck entirely.
[shellcheck]
binary       = "shellcheck"
timeout_secs = 10

# Define macros at lint time (also available via CLI: -D 'name value').
[profiles."rhel-9-x86_64".macros]
mybranch = "production"

Subcommand options that override the config:

Flag Available in Purpose
--config <PATH> lint, check, format, pretty, profile * explicit .rpmspec.toml path
--profile <NAME> lint, check pick the distribution profile (in profile show the name is a positional argument)
-D, --define 'NAME VALUE' lint, check, profile * inject a macro (rpmbuild-style); repeatable
--deny <LINT> / --warn / --allow lint override severity for a single rule; repeatable
--fix / --fix-suggested lint apply machine-applicable (and optionally suggested) rewrites
--format human|json|sarif lint diagnostics output format
--check / --in-place / --diff format dry-run / overwrite / unified-diff modes
--indent N format, pretty indent %if blocks for readability (rpm rejects indented %if — display only)
--format json|yaml / --pretty ast AST dump format
--color auto|always|never top-level and every subcommand ANSI colour control

Exit codes

Command Code Meaning
lint 0 no errors (warnings allowed)
lint 1 one or more error-severity diagnostics
format --check 0 input is already canonical
format --check 1 input would be rewritten
check 1 either lint or format-check failed
profile macro <NAME> 2 single-profile lookup with undefined macro
any non-zero parse error, I/O failure, or invalid CLI

Lint rules

The full catalogue of built-in rules — IDs, default severities, categories, one-line descriptions — lives in doc/lints-list.md. That file is regenerated from the registry by the lints subcommand:

rpm-spec-tool lints                                    # text, grouped by category
rpm-spec-tool lints --format markdown                  # the canonical reference
rpm-spec-tool lints --category correctness --severity deny

--category and --severity are repeatable. Values inside one flag OR-combine; distinct flags AND-combine — for example --category correctness --severity warn lists only warn-severity rules in the correctness category.

The distribution-profile model is documented in doc/profiles.md.

Installation

Pre-built packages

Each tag vX.Y.Z publishes .tar.gz, .deb, and .rpm for Linux x86_64 and aarch64 (plus a SHA256SUMS file) at github.com/johnlepikhin/rpm-spec-tool/releases.

# Debian / Ubuntu derivatives:
sudo apt install ./rpm-spec-tool_X.Y.Z-1_amd64.deb

# RHEL / Fedora derivatives:
sudo dnf install ./rpm-spec-tool-X.Y.Z-1.x86_64.rpm

shellcheck is declared as a Recommends / Suggests dependency — install it if you want the shell-section lints to run.

From source

Requires Rust 1.88 or newer.

# Latest from git:
cargo install --git https://github.com/johnlepikhin/rpm-spec-tool rpm-spec-tool

# From a local clone:
cargo install --path crates/cli

Shell completions

After installation, generate a completion script for your shell with the completions subcommand:

# Bash (system-wide):
rpm-spec-tool completions bash | sudo tee /etc/bash_completion.d/rpm-spec-tool >/dev/null

# Zsh (per-user; ensure the target dir is on $fpath):
rpm-spec-tool completions zsh  > ~/.zsh/completions/_rpm-spec-tool

# Fish (per-user):
rpm-spec-tool completions fish > ~/.config/fish/completions/rpm-spec-tool.fish

# PowerShell:
rpm-spec-tool completions powershell >> $PROFILE

Supported shells: bash, zsh, fish, powershell, elvish.

Pre-commit hook (contributors)

A versioned git pre-commit hook in .githooks/ keeps doc/lints-list.md in sync with the rule registry. Enable it once per clone:

git config core.hooksPath .githooks

The hook fires only when staged files touch crates/analyzer/src/rules/** or the registry, and auto-stages the regenerated markdown. CI runs the same regeneration as a sanity check (lints-doc-check job), so PRs that bypass the hook still get caught.

License

Dual-licensed under either of

at your option.