How to build an RPM using Mock

Building an RPM can be a somewhat annoying, painful experience. There are plenty of pitfalls, but the most annoying, for me at least, is building a package and then trying to install it and realising that it doesn’t work because of some incompatibility in the packages that just happened to be on your build box. One solution to this problem is to use Mock. Mock does a great job of building up an standalone environment, so that you can ‘Fail early’, if you haven’t written your spec file correctly.

Start by installing Mock and other required packages. For example:

$ sudo yum install mock autoconf automake bison bzip2 createrepo \
                   gcc gcc-c++ iconv-devel libcurl-devel libffi-devel \
                   libtool libxml2 libxml2-devel libxslt libxslt-devel \
                   libyaml-devel make openssl-devel patch readline \
                   readline-devel rpm-build zlib zlib-devel rpmdevtools

Mock won’t allow users other than root by default. This is easily fixed by adding your build user to the mock group:

$ sudo usermod -G mock bamboo

From there I usually create an rpmify script. This example comes from packaging a rails application:

#!/usr/bin/env bash
set -x

# Remove previous results in case of build environment not being clean
rm -rf result

echo $BUILD_NUMBER > /tmp/build_number

bundle package

export PACKAGE_NAME=example-rails
rm -rf /tmp/${PACKAGE_NAME}
mkdir -p /tmp/${PACKAGE_NAME}
cp -rf ./* /tmp/${PACKAGE_NAME}/
mkdir -p ~/rpmbuild/SOURCES
tar zcvf ~/rpmbuild/SOURCES/${PACKAGE_NAME}.tar.gz -C /tmp/ ${PACKAGE_NAME}

rpmbuild -bs ${PACKAGE_NAME}.spec

export MOCK_CONFIG=epel-6-x86_64
export MOCK_CONFIG_ROOT=/var/lib/mock/$MOCK_CONFIG-$PACKAGE_NAME-$BUILD_NUMBER

/usr/bin/mock -r $MOCK_CONFIG --uniqueext=$PACKAGE_NAME-$BUILD_NUMBER --init
/usr/bin/mock -r $MOCK_CONFIG --uniqueext=$PACKAGE_NAME-$BUILD_NUMBER --copyin /tmp/build_number /tmp/build_number

/usr/bin/mock -r $MOCK_CONFIG --uniqueext=$PACKAGE_NAME-$BUILD_NUMBER --installdeps ~/rpmbuild/SRPMS/${PACKAGE_NAME}-${BUILD_NUMBER}-1.el6.src.rpm
/usr/bin/mock -r $MOCK_CONFIG  --uniqueext=$PACKAGE_NAME-$BUILD_NUMBER --no-clean ~/rpmbuild/SRPMS/${PACKAGE_NAME}-${BUILD_NUMBER}-1.el6.src.rpm

# Artifacts
rm -rf result
mkdir -p result
cp $MOCK_CONFIG_ROOT/result/*.log result/

if [[ -f $MOCK_CONFIG_ROOT/result/${PACKAGE_NAME}-$BUILD_NUMBER-1.el6.x86_64.rpm ]]; then
  cp $MOCK_CONFIG_ROOT/result/${PACKAGE_NAME}-$BUILD_NUMBER-1.el6.x86_64.rpm  result/
  cp $MOCK_CONFIG_ROOT/result/${PACKAGE_NAME}-$BUILD_NUMBER-1.el6.src.rpm result/
  exitstatus=0
else
  exitstatus=128
fi
/usr/bin/mock -r $MOCK_CONFIG --uniqueext=$PACKAGE_NAME-$BUILD_NUMBER --clean
exit $exitstatus

The script is designed to be used within bamboo, so it does some handling around the artifacts that it produces

Mock looks in /etc/mock for the config that you specify, in this case /etc/mock/epel-6-x86_64.cfg. It is from here that it finds information on how to deploy the dependecies. If you have custom repositories, you’ll want to create your own file.

And voilà, your own professionally built RPM.