rpmfile
The `rpmfile` library (current version 2.1.0, released July 24, 2024) provides tools for inspecting RPM archive files in Python. It is designed to be similar to Python's built-in `tarfile` module, offering an interface to read and extract contents, as well as inspect metadata (headers) of RPM packages. The project maintains an active development status with regular updates addressing parsing correctness and adding features.
Warnings
- breaking Version 2.1.0 fixed incorrect parsing of the first headers block (signature headers) and ensures integer header data values are unpacked as unsigned. This means that applications relying on potentially incorrect signed integer values or misparsed signature data from earlier versions may see changes in behavior or data interpretation when upgrading.
- gotcha Prior to version 2.0.0, `rpmfile` could fail to load localized RPM headers, potentially leading to incomplete or incorrect metadata extraction for packages with internationalized summaries or descriptions.
- gotcha In versions prior to 1.0.8, the library relied on `nlinks` to identify directories within a CPIO archive, which could lead to incorrect identification in certain cases. Version 1.0.8 switched to using mode bits for more accurate directory identification.
Install
-
pip install rpmfile -
pip install 'rpmfile[zstd]' # Or: pip install rpmfile zstandard
Imports
- rpmfile
import rpmfile
- RPMFile
from rpmfile import RPMFile
Quickstart
import rpmfile
import os
# NOTE: Replace 'path/to/your/file.rpm' with an actual RPM file path.
# For a runnable example, you'd typically download a small, public RPM.
# Example: A minimal RPM might not have all headers for 'rpm.headers.keys()'
# but a real one will.
# Create a dummy RPM file for demonstration if you don't have one
# This is a highly simplified placeholder and may not be fully functional
# for all rpmfile operations, but demonstrates the API.
dummy_rpm_path = 'dummy.rpm'
with open(dummy_rpm_path, 'wb') as f:
# A very minimal (likely invalid) RPM header lead for rpmfile to attempt parsing
# Real RPMs are significantly more complex.
f.write(b'\xed\xab\xee\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
try:
with rpmfile.open(dummy_rpm_path) as rpm:
print(f"RPM Name: {rpm.headers.get('name', 'N/A')}")
print(f"RPM Version: {rpm.headers.get('version', 'N/A')}")
print(f"RPM Release: {rpm.headers.get('release', 'N/A')}")
# List members in the archive
print("\nArchive Members:")
members = rpm.getmembers()
if members:
for member in members:
print(f" - {member.name}")
else:
print(" (No members found or could not parse)")
# Example of extracting a file (will fail for dummy.rpm as no actual files)
# if './usr/bin/script' in [m.name for m in members]:
# fd = rpm.extractfile('./usr/bin/script')
# print(f"\nContent of ./usr/bin/script:\n{fd.read().decode()}")
except rpmfile.BadRpmfile as e:
print(f"Error opening RPM file: {e}. The dummy.rpm is likely too incomplete for full parsing.")
finally:
# Clean up the dummy file
if os.path.exists(dummy_rpm_path):
os.remove(dummy_rpm_path)