--- category: en type: paper layout: paper tags: archlinux, configuration, linux title: Creating own repository short: creating-custom-repo description: It is a short paper devoted to creation own ArchLinux repository. ---

Prepare

First find a server and desire to have sex with it. It is recommended to use Archlinux on it, but it is not necessarily - because you may create special root for Archlinux. Also you need two packages, devtools and pacman:

{% highlight bash %} pacman -Sy devtools {% endhighlight %}

devtools is script set for building automation in the clean chroot. I think most of Arch maintainers use it.

Let's create working directories and set colors:

{% highlight bash %} # colors if [ ${USECOLOR} == "yes" ]; then black='\e[0;30m' bblack='\e[1;30m' red='\e[0;31m' bred='\e[1;31m' green='\e[0;32m' bgreen='\e[1;32m' yellow='\e[0;33m' byellow='\e[1;33m' blue='\e[0;34m' bblue='\e[1;34m' purple='\e[0;35m' bpurple='\e[1;35m' cyan='\e[0;36m' bcyan='\e[1;36m' white='\e[0;37m' bwhite='\e[1;37m' cclose='\e[0m' fi export USECOLOR # directories if [ ! -d "${PREPAREDIR}" ]; then [ -e "${PREPAREDIR}" ] && error_mes "file" "${PREPAREDIR}" echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${PREPAREDIR}'${cclose}" mkdir -p "${PREPAREDIR}" || error_mes "unknown" fi if [ ! -d "${REPODIR}" ]; then [ -e "${REPODIR}" ] && error_mes "file" "${REPODIR}" echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${REPODIR}'${cclose}" mkdir -p "${REPODIR}/"{i686,x86_64} || error_mes "unknown" fi if [ ! -d "${REPODIR}/i686" ]; then [ -e "${REPODIR}/i686" ] && error_mes "file" "${REPODIR}/i686" echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${REPODIR}/i686'${cclose}" mkdir -p "${REPODIR}/i686" || error_mes "unknown" fi if [ ! -d "${REPODIR}/x86_64" ]; then [ -e "${REPODIR}/x86_64" ] && error_mes "file" "${REPODIR}/x86_64" echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${REPODIR}/x86_64'${cclose}" mkdir -p "${REPODIR}/x86_64" || error_mes "unknown" fi if [ ! -d "${STAGINGDIR}" ]; then [ -e "${STAGINGDIR}" ] && error_mes "file" "${STAGINGDIR}" echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${STAGINGDIR}'${cclose}" mkdir -p "${STAGINGDIR}" || error_mes "unknown" fi {% endhighlight %}

${REPODIR}/{i686,x86_64} are directories for repository, ${PREPAREDIR} is directory where compiled packages will be stored, ${STAGINGDIR} is one where packages will be built.

A bit of theory

Create directory, share it (using ftp, for example). It has two subdirectories - i686 and x86_64 - for each architecture respectively. And fill them with a set of packages.

Updating repository may be split into the following steps:

  1. Creating PKGBUILDs (or updating them from AUR).
  2. Packages building for each architecture in clean chroot.
  3. Packages signing.
  4. Creating the list of packages.
  5. Repository update:
    1. Removal old packages from repository.
    2. Copying new packages
    3. Repository update.
  6. Cleaning.

Creating PKGBUILDs

Download source tarballs from AUR:

{% highlight bash %} cd "${STAGINGDIR}" yaourt -G package-name {% endhighlight %}

Packages building

Build each package automatically:

{% highlight bash %} func_build() { if [ ${USECOLOR} == "yes" ]; then bblue='\e[1;34m' bwhite='\e[1;37m' cclose='\e[0m' fi PREPARE="$1" ROOT="$2" eval $(/usr/bin/grep 'arch=' PKGBUILD) eval $(/usr/bin/grep 'pkgname=' PKGBUILD) echo -e "${bwhite}[II] ${bblue}=>${cclose} Building ${bwhite}${pkgname}${cclose}" if echo ${arch} | /usr/bin/grep 'any' -q; then LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-i686-build -r "${ROOT}" -c else eval $(/usr/bin/grep 'pkgname=' PKGBUILD) if echo ${pkgname} | /usr/bin/grep lib32 -q; then LC_MESSAGES=C /usr/bin/sudo /usr/bin/multilib-staging-build -r "${ROOT}" -c else if /usr/bin/grep 'lib32' PKGBUILD -q; then LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-i686-build -r "${ROOT}" -c LC_MESSAGES=C /usr/bin/sudo /usr/bin/multilib-staging-build -r "${ROOT}" -c else LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-i686-build -r "${ROOT}" -c LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-x86_64-build -r "${ROOT}" -c fi fi fi /usr/bin/cp *.pkg.tar.xz "${PREPARE}" } export -f func_build # building echo -e "${bwhite}[II]${cclose} Building packages" cd "${STAGINGDIR}" /usr/bin/find -name 'PKGBUILD' -type f -execdir /usr/bin/bash -c "func_build "${PREPAREDIR}" "${ROOTDIR}"" \; {% endhighlight %}

It is recommended to add the following lines to /etc/sudoers:

{% highlight bash %} username ALL=NOPASSWD: /usr/bin/staging-i686-build username ALL=NOPASSWD: /usr/bin/staging-x86_64-build username ALL=NOPASSWD: /usr/bin/multilib-staging-build {% endhighlight %}

Packages signing

{% highlight bash %} # signing if [ ${USEGPG} == "yes" ]; then echo -e "${bwhite}[II]${cclose} Signing" cd "${PREPAREDIR}" for PACKAGE in $(/usr/bin/find . -name '*.pkg.tar.xz'); do /usr/bin/gpg -b ${PACKAGE} done fi {% endhighlight %}

It is recommended to configure gpg-agent.

Creating the list of packages

{% highlight bash %} # creating packages list cd "${PREPAREDIR}" i686_PACKAGES=$(/usr/bin/find * -name '*-i686.pkg.tar.xz' -o -name '*-any.pkg.tar.xz') x86_64_PACKAGES=$(/usr/bin/find * -name '*-x86_64.pkg.tar.xz' -o -name '*-any.pkg.tar.xz') echo -e "${bwhite}[II] ${bblue}=>${cclose} i686 packages: \n${bwhite}${i686_PACKAGES}${cclose}" echo -e "${bwhite}[II] ${bblue}=>${cclose} x86_64 packages: \n${bwhite}${x86_64_PACKAGES}${cclose}" {% endhighlight %}

Repository update

Here is a function for removal packages from database and repository:

{% highlight bash %} func_remove() { PACKAGE="$1" REPODIR="$2" /usr/bin/rm -f "${REPODIR}/${PACKAGE}"{,.sig} } {% endhighlight %}

i686 repository update:

{% highlight bash %} # updating i686 repo echo -e "${bwhite}[II]${cclose} Updating ${bwhite}i686${cclose} repo" cd "${REPODIR}/i686" for PACKAGE in ${i686_PACKAGES}; do PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/i686/${PACKAGE}") func_remove "${PACKAGE}" "${REPODIR}/i686" /usr/bin/cp "${PREPAREDIR}/${PACKAGE}" . [ ${USEGPG} == "yes" ] && /usr/bin/cp "${PREPAREDIR}/${PACKAGE}.sig" . /usr/bin/repo-add ${DBNAME}.db.tar.gz "${PACKAGE}" /usr/bin/repo-add --files ${DBNAME}.files.tar.gz "${PACKAGE}" done {% endhighlight %}

x86_64 repository update:

{% highlight bash %} # updating x86_64 repo echo -e "${bwhite}[II]${cclose} Updating ${bwhite}x86_64${cclose} repo" cd "${REPODIR}/x86_64" for PACKAGE in ${x86_64_PACKAGES}; do PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/x86_64/${PACKAGE}") func_remove "${PACKAGE}" "${REPODIR}/x86_64" /usr/bin/cp "${PREPAREDIR}/${PACKAGE}" . [ ${USEGPG} == "yes" ] && /usr/bin/cp "${PREPAREDIR}/${PACKAGE}.sig" . /usr/bin/repo-add ${DBNAME}.db.tar.gz "${PACKAGE}" /usr/bin/repo-add --files ${DBNAME}.files.tar.gz "${PACKAGE}" done {% endhighlight %}

Cleaning

{% highlight bash %} # clear cd "${PREPAREDIR}" /usr/bin/rm -rf * cd "${STAGINGDIR}" /usr/bin/rm -rf * {% endhighlight %}

File

Here is the scripts. Download source tarballs and run script (editing variables if it is necessary).

Repository usage

Just add following lines to /etc/pacman.conf:

{% highlight bash %} [$REPONAME] Server = ftp://$REPOADDRESS/repo/$arch {% endhighlight %}