---
category: ru
type: paper
hastr: true
layout: paper
tags: archlinux, настройка, linux
title: Создание собственного репозитория
short: creating-custom-repo
description: Небольшая статья, посвященная созданию собственного репозитория для Archlinux.
---
<h2><a href="#prepare" class="anchor" id="prepare"><span class="octicon octicon-link"></span></a>Подготовка</h2>
<p>Для начала находим сервер и желание с ним заниматься сексом. Для простоты, лучше, чтобы там стоял Archlinux, хотя, это и не совсем обязательно (можно создать отдельный корень под Arch). Из пакетов, пожалуй, нам понадобится только два, <code>devtools</code> и сам <code>pacman</code>:</p>

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

<p><a href="https://www.archlinux.org/packages/devtools/" title="Пакет Archlinux">devtools</a> - набор скриптов, предназначенный для автоматизации сборки пакетов в чистом чруте. Думаю, большинство мейнтейнеров Arch'а пользуются им.</p>
<p>Создадим рабочие директории и установим цвета:</p>

{% highlight bash %}
# цвета
if [ ${USECOLOR} == "yes" ]; then
  bblue='\e[1;34m'
  bwhite='\e[1;37m'
  cclose='\e[0m'
fi
export USECOLOR
# директории
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 %}

<p>Директории <code>${REPODIR}/{i686,x86_64}</code> для самого репозитория, <code>${PREPAREDIR}</code> - директория, где будут лежать собранные пакеты, <code>${STAGINGDIR}</code> - директория, откуда будут собираться пакеты.</p>

<h2><a href="#theory" class="anchor" id="theory"><span class="octicon octicon-link"></span></a>Немного теории</h2>
<p>Создаем директорию, расшариваем ее (например, по <a href="/ru/2014/03/06/site-changes/" title="Статья про изменения сайта">ftp</a>). В ней две субдиректории - <code>i686</code> и <code>x86_64</code>, для каждого типа архитектур соответственно. И наполняем их набором пакетов по Вашему усмотрению.</p>

<p>Процесс обновления репозитория можно разбить на следующие части:</p>
<ol>
  <li>Создание PKGBUILD'ов (обновление их из AUR'а).</li>
  <li>Сборка пакетов для различных архитектур в чистом чруте.</li>
  <li>Подписывание пакетов.</li>
  <li>Создание списка пакетов.</li>
  <li>Обновление репозиториев:
    <ol><li>Удаление старых пакетов из репозитория.</li>
    <li>Копирование новых пакетов.</li>
    <li>Обновление базы.</li></ol>
    </li>
  <li>Очистка.</li>
</ol>

<p>Теперь по шагам.</p>

<h3><a href="#pkgbuild" class="anchor" id="pkgbuild"><span class="octicon octicon-link"></span></a>Создание PKGBUILD'ов</h3>
<p>Скачаем исходники для всех нужных пакетов из AUR'а:</p>

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

<h3><a href="#building" class="anchor" id="building"><span class="octicon octicon-link"></span></a>Сборка пакетов</h3>
<p>Автоматически соберем каждый пакет:</p>

{% highlight bash %}
func_build() {
  if [ ${USECOLOR} == "yes" ]; then
    _bblue='\e[1;34m'
    _bwhite='\e[1;37m'
    _cclose='\e[0m'
  fi
  _PREPAREDIR="$1"
  _ROOTDIR="$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 "${_ROOTDIR}" -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 "${_ROOTDIR}" -c
    else
      if /usr/bin/grep 'lib32' PKGBUILD -q; then
        LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-i686-build -r "${_ROOTDIR}" -c
        LC_MESSAGES=C /usr/bin/sudo /usr/bin/multilib-staging-build -r "${_ROOTDIR}" -c
      else
        LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-i686-build -r "${_ROOTDIR}" -c
        LC_MESSAGES=C /usr/bin/sudo /usr/bin/staging-x86_64-build -r "${_ROOTDIR}" -c
      fi
    fi
  fi
  /usr/bin/cp *.pkg.tar.xz "${_PREPAREDIR}"
}
export -f func_build

# сборка
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 %}

<p>Для удобства рекомендую добавить в файл <code>/etc/sudoers</code> следующие строки:</p>

{% 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 %}

<h3><a href="#signing" class="anchor" id="signing"><span class="octicon octicon-link"></span></a>Подпись пакетов</h3>

{% highlight bash %}
# подпись
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 %}

<p>Для удобства рекомендую настроить <a href="https://wiki.archlinux.org/index.php/GPG#gpg-agent" title="ArchWiki">gpg-agent</a>.</p>

<h3><a href="#list" class="anchor" id="list"><span class="octicon octicon-link"></span></a>Создание списка пакетов</h3>

{% highlight bash %}
# создание списка пакетов
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 %}

<h3><a href="#updating" class="anchor" id="updating"><span class="octicon octicon-link"></span></a>Обновление репозиториев</h3>
<p>Функция для удаления пакетов из базы данных и из репозитория:</p>

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

<p>Обновление репозитория <code>i686</code>:</p>

{% highlight bash %}
# обновление репозитория i686
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 "${PREPAREDIR}/${PACKAGE}")
  for PKG in $(/usr/bin/find "${REPODIR}/i686" -name "${PKGNAME}"'*.pkg.tar.xz'); do
    _PKGNAME=$(/usr/bin/package-query -p -f %n "${PKG}")
    [ "${PKGNAME}" == "${_PKGNAME}" ] && func_remove "${PKG}"
  done
  /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 %}

<p>Обновление репозитория <code>x86_64</code>:</p>

{% highlight bash %}
# обновление репозитория x86_64
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 "${PREPAREDIR}/${PACKAGE}")
  for PKG in $(/usr/bin/find "${REPODIR}/x86_64" -name "${PKGNAME}"'*.pkg.tar.xz'); do
    _PKGNAME=$(/usr/bin/package-query -p -f %n "${PKG}")
    [ "${PKGNAME}" == "${_PKGNAME}" ] && func_remove "${PKG}"
  done
  /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 %}

<h3><a href="#clear" class="anchor" id="clear"><span class="octicon octicon-link"></span></a>Очистка</h3>

{% highlight bash %}
# очистка
cd "${PREPAREDIR}"
/usr/bin/rm -rf *
cd "${STAGINGDIR}"
/usr/bin/rm -rf *
{% endhighlight %}

<h3><a href="#symlinks" class="anchor" id="symlinks"><span class="octicon octicon-link"></span></a>Создание симлинков</h3>
<p>Вы можете захотеть создать директорию, которая будет содержать симлинки на актуальные версии пакетов с именами, не содержащими версии:</p>

{% highlight bash %}
# создание симлинков
if [ ${SYMLINK} == "yes" ]; then
  echo -e "${bwhite}[II]${cclose} Creating symlinks"
  if [ ! -d "${REPODIR}/non-versioned" ]; then
    [ -e "${REPODIR}/non-versioned" ] && error_mes "file" "${REPODIR}/non-versioned"
    echo -e "${bwhite}[II] ${bblue}Creating directory ${bwhite}'${REPODIR}/non-versioned'${cclose}"
    mkdir -p "${REPODIR}/non-versioned" || error_mes "unknown"
  fi
  cd "${REPODIR}/non-versioned"
  for PACKAGE in ${i686_PACKAGES}; do
    PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/i686/${PACKAGE}")
    /usr/bin/ln -sf "../i686/${PACKAGE}" "${PKGNAME}-i686.pkg.tar.xz"
  done
  for PACKAGE in ${x86_64_PACKAGES}; do
    PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/x86_64/${PACKAGE}")
    /usr/bin/ln -sf "../x86_64/${PACKAGE}" "${PKGNAME}-x86_64.pkg.tar.xz"
  done
fi
{% endhighlight %}

<h3><a href="#file" class="anchor" id="file"><span class="octicon octicon-link"></span></a>Файл</h3>
<p><a href="https://github.com/arcan1s/repo-scripts" title="GitHub">Скрипты</a> целиком. Скачиваем исходники для пакетов, запускаем скрипт (при необходимости, редактируем переменные) и радуемся жизни.</p>

<h2><a href="#using" class="anchor" id="using"><span class="octicon octicon-link"></span></a>Использование репозитория</h2>
<p>Просто добавляем в файл <code>/etc/pacman.conf</code> следующие строки:</p>

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