Implementing build policies with spec-helper

Contents

How it works

Spec-helper provides a set ot scripts that are automatically launched during the build process to ease the creation of rpm packages conforming to ROSA Linux packaging policies. The spec-helper package also includes several scripts that can be used by maintainers to automate routine tasks.

For example, ROSA Linux policy states that man pages should be compressed with xz, amongst others. In order to ease the creation of packages, and to keep them as vendor neutral as possible, we use a hook in rpm to automatically enforce the policy.

Take a look at /usr/lib/rpm/brp-* files. These are the "build root policies", which is a set of rules to be applied after the build. The configuration of the BRP is made by using a macro, %_os_install_post. For ROSA Linux, you can see it in /usr/lib/rpm/.

So, we see that most of the /usr/lib/rpm/brp-* files are run when an rpm is built.

Scripts used by spec-helper are located at /usr/share/spec-helper folder. The scripts which will be actually launched are set in the /etc/rpm/macros.d/spec-helper.macros file. We will describe how to add a script to spec-helper.

Writing the script

First, find a name for your script. To give a full exemple, we will add a script that runs pngcrush on each png in an rpm. Let's call it png_crush_rpm. Don't use pngcrush, because this is already a valid executable on the system. Since /usr/share/spec_helper is added to the path by the script, it will not work as expected.

It seems that you have a choice for the language. In the current spec-helper we have scripts in perl, bash and python script. In the examples below, we will use shell.

You can use any language, but remember that using a new language will add a dependancy to the spec-helper rpm. Using a new program, such as pngcrush will also add more dependencies, that should be added to the rpm. Please keep this in mind.

So all you have to do is to apply your script to $RPM_BUILD_ROOT. Don't forget to check if the variable is defined, and it is a valid directory. You should exit in case of problem.

#!/bin/sh

# test if $RPM_BUILD_ROOT is set
if [ -z $RPM_BUILD_ROOT ]; then
   exit 0
fi;

# check if it is a valid directory.
[ -d $RPM_BUILD_ROOT ] || exit 0

# find each png, and crush it.
for i in ind $RPM_BUILD_ROOT -type f -name '*.png' ; do
   pngcrush -q $i $i.new
   mv -f $i.new $i
done;

Do not forget to set the executable (+x) bit on the file.

Test it by defining RPM_BUILD_ROOT by hand, and check if this is correct.

Adding the test to spec-helper

Now we should add it to spec-helper.

You should add an option to be able to not run the script to spec-helper. So add these other options:

echo "-png don't run pngcrsuh on png." 1>&2

and

-png) DONT_PNG_CRUSH=1;;

in the switch/case.

Now all that remains is to invoke your script:

test -z "$DONT_PNG_CRUSH" && echo -n "Recompressing png..." && png_crush_rpm && echo "done"

And now, rpm will run your script when rebuilding.

Test it, and if you find it is useful, send your patch to ROSA Linux developers.

Disabling a build policy in a specfiles

Sometimes, build policies can have an unwanted effect. One example is when you do not want to strip your executable, for debugging purposes. You can disable it by setting the correct variable in the %install section :

%install
rm -rf %{buildroot}
%makeinstall
....
# prevent the stripping of executable 
export DONT_STRIP=1

%clean

See the /etc/rpm/macros.d/spec-helper.macros file for the list of possible variables. Here is a list ( may not be current ) :

Standalone scripts for manual use

Spec-helper contains several standalone scripts that are not launched automatically during the build but are intended to be run by maintainers manually.

spec-cleaner

Spec-cleaner scripts aims to clean the spec file by removing redundant and obsolete content. In particular, this script:

Note that by default spec-cleaner drops %changelog section from spec files, since nowadays package changelogs in ABF are generated from Git commit history and most spec files contain only ancient changelogs. But if you do not want spec-cleaner to drop %changelog from your specs, just set the SPEC_LEAVE_CHANGELOG variable to 1.

rediff_patch

This script tries to rediff an existing patch against a new tarball with source code. Usage instructions are like the following:

  1. rediff_patch should be launched in the folder of a cloned Git project, where spec file and patches reside. Spec file is used to determine how the patch should be applied;
  2. the new tarball should be placed in the same folder;
  3. the script should be launched in the following way:
 rediff_patch <patch_ro_rediff> <tarball>

If you folder contains only one tarball, then you can omit second argument.

During its work, rediff_patch creates rediff_patch folder, unpacks tarball into it and tries to apply the patch to the unpacked content. To apply the patch, it uses parameters extracted from the spec file, but adds «--force» option and uses default system value for the «fuzz» option (remember that rpmbuild uses «--fuzz=0» by default). Currently the script only handles situation when tarball has a single top-lever folder; it will reject to work with tar bombs

If everything goes fine, then you will find a new patch (with the «.new» suffix) near the old one. rediff_patch folder with the whole content will be removed.

If something goes wrong (e.g., patch was applied only partially and some hunks failed) then you will be left with rediff_patch folder containing two subfolders — the original one and the new one, where a patch was tried to be applied So you will be able to analyze the reasons of failures and finish rediff manually.

As our practice shows, in reality most patches fail to rediff completely automatically, even with «--force» and more soft «--fuzz». But even rediff_patch managed to prepare a new patch for you, do not forget to check this patch carefully — '--force' sometimes leads to undesired results. But even if rediff_patch failed — well, at least we have saved some time, since it has unpacked tarball for us and performed a first attempt to apply the patch.



Note:
This page is based on the Mandriva spec-helper description.