Rpmrebuild FTW!

A problem that I faced today, summarized in a tweet:

After some Googling, I found this blog post about a tool called rpmrebuild.

I decided to give it a go on the Oracle-supplied RPM for JDK6. It is called jdk-6u45-linux-amd64.rpm in the current directory.

$ rpmrebuild -n --change-spec-preamble='sed -e "s/^Name:.*/Name:jdk6/"' -p jdk-6u45-linux-amd64.rpm
result: /home/martijn/rpmbuild/RPMS/x86_64/jdk6-1.6.0_45-fcs.x86_64.rpm

Comparison of the original and resulting RPMs showed the following:

  • file size of the original RPM is 57MB, the result is 50MB
  • Reported Size in the output of rpm -qpi only differs 60kB
  • Name, Build Date, Build Host and Size are the only meta-information fields that changed
  • The file list of both RPMs (output of rpm -qpl) is exactly the same

This looks good, so let’s try installation:

$ sudo rpm -ivh jdk6-1.6.0_45-fcs.x86_64.rpm                                                          [0]
Preparing...                ########################################### [100%]
        file /etc/.java/.systemPrefs/.system.lock from install of jdk6-2000:1.6.0_45-fcs.x86_64 conflicts with file from package jdk-2000:1.7.0_21-fcs.x86_64
        file /etc/.java/.systemPrefs/.systemRootModFile from install of jdk6-2000:1.6.0_45-fcs.x86_64 conflicts with file from package jdk-2000:1.7.0_21-fcs.x86_64
        file /etc/init.d/jexec from install of jdk6-2000:1.6.0_45-fcs.x86_64 conflicts with file from package jdk-2000:1.7.0_21-fcs.x86_64

These file conflicts were to be expected, since the installed JDK7 also ships them. So we need more trickery, in the form of a –change-files option to rpmrebuild.

export RPMREBUILD_TMPDIR=`mktemp -d`
rpmrebuild -n \\
  --change-files="sed -i '/^%config.*\"\\/etc/d' $RPMREBUILD_TMPDIR/work/files.1" \\
  --change-spec-preamble='sed -e "s/^Name:.*/Name:jdk6/"' \\
  -p jdk-6u45-linux-amd64.rpm

$RPMREBUILD_TMPDIR/work/files.1 is the file that lists all the files to be included in the RPM. Using sed -i, we remove all the lines from that file that name a configuration file under /etc, represented by the regular expression /^%config.*\"\/etc/.

The resulting RPM seems to install nicely on a RHEL6 system that already has a Java7 SDK installed. Win! Of course, for the sake of consistency, I need to do the same thing to the Java7 RPM. Unfortunately, the Java7 RPM had one more problem, being that the postinstall scriptlet would give errors, due to the files we deleted now being missing. My final invocation for the Java7 RPM is as follows:

export RPMREBUILD_TMPDIR=`mktemp -d`
rpmrebuild -n \\
  --change-spec-preamble='sed -e "s/^Name:.*/Name:jdk7/"' \\
  --change-files="\\
    sed -i '/^%config.*\\"\\/etc/d' $RPMREBUILD_TMPDIR/work/files.1; \\
    sed -i 's/\\/etc\\/init.d\\/jexec start/#\\/etc\\/init.d\\/jexec start/' $RPMREBUILD_TMPDIR/work/post.1; \\
    sed -i 's/\\/usr\\/lib\\/lsb\\/install_initd jexec/true; #\\/usr\\/lib\\/lsb\\/install_initd jexec/' $RPMREBUILD_TMPDIR/work/post.1; \\
    sed -i 's/\\/sbin\\/chkconfig --add/true; #\\/sbin\\/chkconfig --add/' $RPMREBUILD_TMPDIR/work/post.1" \\
  -p jdk-7u21-linux-x64.rpm