Поддержка кастомного репозитория archlinux

Решил я тут некоторое время назад избавиться от всех возможных (приложений, опубликованных в открытом доступе) пакетов из аура и перенести их в свой специально созданный репозиторий. В этой теме я коснусь темы автоматизации поддержки своего репозитория, т.к. пакман по дефолту предоставляет только утилиты repo-remove и repo-add, которые для автоматизации не совсем годятся (хотя, конечно, будут использованы).

warning по сути, все ниже написанное - лютый быдлокод и велосипед костыльного типа.

1. Обновление пакетов.
1.1. Зависимости
В том варианте, который я предлагаю, предполагается наличие двух пакетов в системе (помимо base, base-devel): yaourt для скачивания PKGBUILD'ов (package-query - зависимость йогурта - для запросов к базам данных), devtools для сборки пакетов. Резюмируя:
pacman -S yaourt devtools
1.2. Переменные
Функция, вызывающаяся при ошибке (сообщение + выход из скрипта):
error_mes() {
  case "$1" in
    "config"    ) echo "[EE] Configuration file is not set"                   ;;
    "file"      ) echo "[EE] '$2' is a file"                                  ;;
    "flag"      ) echo "[EE] Unknown flag"                                    ;;
    "unknown"   ) echo "[EE] Unknown error"                                   ;;
  esac
  exit 1
}
Сами переменные:
DBNAME="custom"
PREPAREDIR="${HOME}/arch/prepare"
REPODIR="${HOME}/arch/repo"
ROOTDIR="${HOME}/arch/root"
STAGINGDIR="${HOME}/arch/staging/"
SYMLINK="yes"
USEGPG="yes"
Объяснение директорий чуть ниже. DBNAME - имя репозитория, SYMLINK - ниже, USEGPG - подписывать или нет пакеты.
1.3. Структура директорий
arch
├── prepare
├── repo
│   ├── i686
│   ├── non-versioned
│   └── x86_64
├── root
└── staging
repo/{i686,x86_64} - собственно репозиторий, смысл repo/non-versioned раскрою чуть позже, root - директория для сборки пакетов, prepare - директория с собранными пакетами, staging - директория, из которой пакеты будут собираться.
Создадим директории =)
if [ ! -d "${PREPAREDIR}" ]; then
  [ -e "${PREPAREDIR}" ] && error_mes "file" "${PREPAREDIR}"
  /usr/bin/mkdir -p "${PREPAREDIR}" || error_mes "unknown"
fi
if [ ! -d "${REPODIR}" ]; then
  [ -e "${REPODIR}" ] && error_mes "file" "${REPODIR}"
  /usr/bin/mkdir -p "${REPODIR}/"{i686,x86_64} || error_mes "unknown"
fi
if [ ! -d "${REPODIR}/i686" ]; then
  [ -e "${REPODIR}/i686" ] && error_mes "file" "${REPODIR}/i686"
  /usr/bin/mkdir -p "${REPODIR}/i686" || error_mes "unknown"
fi
if [ ! -d "${REPODIR}/x86_64" ]; then
  [ -e "${REPODIR}/x86_64" ] && error_mes "file" "${REPODIR}/x86_64"
  /usr/bin/mkdir -p "${REPODIR}/x86_64" || error_mes "unknown"
fi
if [ ! -d "${STAGINGDIR}" ]; then
  [ -e "${STAGINGDIR}" ] && error_mes "file" "${STAGINGDIR}"
  /usr/bin/mkdir -p "${STAGINGDIR}" || error_mes "unknown"
fi
1.4. Процесс сборки
  1. Сборка пакетов под нужные архитектуры в чистом чруте.
  2. Подписывание пакетов, если нужно.
  3. Обновление репозитория: удаление старых пакетов, копирование новых, обновление базы.
1.5. Получение PKGBUILD'ов
Автоматизация этого этапа будет рассмотрена в п.2. В общем случае выглядит примерно так:
cd "${STAGINGDIR}"
yaourt -G package-name
1.6. Сборка пакетов
Сама фукнция сборки:
func_build() {
  _PREPAREDIR="$1"
  _ROOTDIR="$2"
  eval $(/usr/bin/grep 'arch=' PKGBUILD)
  eval $(/usr/bin/grep 'pkgname=' PKGBUILD)
  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
Автоматически распознает под какие архитекторы и как надо собирать пакет. На вход получает два параметра - директория, где будут лежать готовые пакеты, и директория, где будет создан чистый рут. Так как в процессе выполняется чрут в директорию, то нужны права рута. Предлагаю для упрощения внести следующие строки в /etc/sudoers:
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
Процесс сборки:
cd "${STAGINGDIR}"
/usr/bin/find -name 'PKGBUILD' -type f -execdir /usr/bin/bash -c "func_build "${PREPAREDIR}" "${ROOTDIR}"" \;
1.7. Подписывание (если нужно)
Все простенько. Только нужно gpg настроить и лучше настроить gpg-agent
if [ ${USEGPG} == "yes" ]; then
  cd "${PREPAREDIR}"
  for PACKAGE in $(/usr/bin/find . -name '*.pkg.tar.xz'); do
    /usr/bin/gpg -b ${PACKAGE}
  done
fi
Альтернативный вариант - подписывать только базу данных - оставлю на самостоятельно решение (читать справку по repo-add).
1.8. Создание списка пакетов, обновление репозитория
Получаем список того, что насобирали:
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')
Функция для удаления пакетов:
func_remove() {
  _PACKAGE="$1"
  /usr/bin/rm -f "${_PACKAGE}"{,.sig}
}
Обновление i686 пакетов:
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
и аналогично для x86_64:
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
1.9. Создание симлинков (если нужно)
Пакеты, ессно, версионные, но иногда хочется давать прямые постоянные ссылки на нужные пакеты. Для этого я решил создать отдельную директорию и понаделать там симлинков =) Процесс обновления симлинков выглядит так:
if [ ${SYMLINK} == "yes" ]; then
  if [ ! -d "${REPODIR}/non-versioned" ]; then
    [ -e "${REPODIR}/non-versioned" ] && error_mes "file" "${REPODIR}/non-versioned"
    /usr/bin/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
1.10. Очистка
cd "${PREPAREDIR}"
/usr/bin/rm -rf *
cd "${STAGINGDIR}"
/usr/bin/rm -rf *
PGP 0x31361F01
arcanisrepo
2. Автоматическое получение списка пакетов
2.1. Переменные
IGNORELIST=""
REPODIR="${HOME}/arch/repo"
STAGINGDIR="${HOME}/arch/staging/"
из нового IGNORELIST - мало ли, вдруг какие то пакеты не хотим пересобирать. В моем варианте, это список пакетов, разделенный ;;
Директории:
if [ ! -d "${REPODIR}" ]; then
  [ -e "${REPODIR}" ] && error_mes "file" "${REPODIR}"
  mkdir -p "${REPODIR}/"{i686,x86_64} || error_mes "unknown"
fi
if [ ! -d "${REPODIR}/i686" ]; then
  [ -e "${REPODIR}/i686" ] && error_mes "file" "${REPODIR}/i686"
  /usr/bin/mkdir -p "${REPODIR}/i686" || error_mes "unknown"
fi
if [ ! -d "${REPODIR}/x86_64" ]; then
  [ -e "${REPODIR}/x86_64" ] && error_mes "file" "${REPODIR}/x86_64"
  /usr/bin/mkdir -p "${REPODIR}/x86_64" || error_mes "unknown"
fi
if [ ! -d "${STAGINGDIR}" ]; then
  [ -e "${STAGINGDIR}" ] && error_mes "file" "${STAGINGDIR}"
  mkdir -p "${STAGINGDIR}" || error_mes "unknown"
fi
2.2. Функция, отвечающая за обновление
func_update() {
  _PKGNAME="$1"
  _PKGVER="$2"
  _REPODIR="$3"

  if echo ${_PKGNAME} | /usr/bin/grep -q "\-bzr\|\-git\|\-svn"; then
    return 1
  fi
  NEWVER=$(/usr/bin/package-query -A -f %V "${_PKGNAME}")
  if [ -z "${NEWVER}" ]; then
    return 1
  fi
  if [ "${_PKGVER}" == "${NEWVER}" ]; then
    echo -e "[II] ${_PKGNAME} is up-to-date"
  else
    echo -e "[II] ${_PKGNAME} is out-of-date"
    /usr/bin/yaourt -G aur/${_PKGNAME} --noconfirm &> /dev/null
  fi
}
VCS пакеты не обновляются (ручками, ручками). Получение версии пакета из аура, сравнение с локальной версией и получение тарбола, если пакет устарел.
2.3. Получение списка пакетов
Создание спискоты для списка игнорируемых пакетов
IGNORELIST=$(echo "${IGNORELIST}" | sed "s/;;/\\\|/g")
Обновление локальной базы (нужен sudo!)
/usr/bin/yaourt -Sy
Получение списка пакетов для разных архитектур
/usr/bin/rm -f "${STAGINGDIR}/pkglist"
cd "${REPODIR}/i686"
/usr/bin/find . -name '*.pkg.tar.xz' | /usr/bin/grep -v "$IGNORELIST" | /usr/bin/cut -c 3- >> "${STAGINGDIR}/pkglist"
cd "${REPODIR}/x86_64"
/usr/bin/find . -name '*.pkg.tar.xz' | /usr/bin/grep -v "$IGNORELIST" | /usr/bin/cut -c 3- >> "${STAGINGDIR}/pkglist"
2.4. Проверка версий
Получаем имя пакета и его версию в своем репозитории. Запускаем с этими данными функцию func_update:
cd "${STAGINGDIR}"
for PACKAGE in $(cat pkglist); do
  if echo "${PACKAGE}" | grep -q "\-i686.pkg.tar.xz\|\-any.pkg.tar.xz"; then
    PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/i686/${PACKAGE}")
    PKGVER=$(/usr/bin/package-query -p -f %V "${REPODIR}/i686/${PACKAGE}")
  else
    PKGNAME=$(/usr/bin/package-query -p -f %n "${REPODIR}/x86_64/${PACKAGE}")
    PKGVER=$(/usr/bin/package-query -p -f %V "${REPODIR}/x86_64/${PACKAGE}")
  fi
  func_update "${PKGNAME}" "${PKGVER}" "${REPODIR}"
done
/usr/bin/rm -f "${STAGINGDIR}/pkglist"
2.5. Переход к п.1
Если что то есть, значит на5до собирать:
cd "${STAGINGDIR}"
if [[ $(/usr/bin/find . -type d | /usr/bin/wc -l) > 1 ]]; then
  /usr/bin/repo-update -c "${CONF_FILE}"
fi
2.6. Ручная сборка
Если мы хотим пересобрать какой то пакет по каким то там причинам (например, VCS), то перед запуском этого скрипта нужно всего лишь Выполнить команду из п.1.5:
cd "${STAGINGDIR}"
yaourt -G package-name
PGP 0x31361F01
arcanisrepo
3. Ссылки
Немного есть у меня в блоге (чуть чуть в другом виде и только про п.1).
Скрипты (с файлом настроек и цветами) доступны на github.
Для совсем ленивых есть уже собранный пакет

4. Использование скриптов
Для проверки и сборки устаревших пакетов просто набираем
repo-check
Для только сборки тех пакетов, тарболы которых мы предварительно сами закинули:
repo-update

5. Немного о расшаривании
В моем случае, это добро работает по ftp, который поднят через vsftpd с анонимным доступом. Защита от записи осуществляется путем биндинга директории repo в директорию ftp с правами ro (просто на ftp есть еще директория с правами rw). Конфиг (/etc/vsftpd.conf) выглядит примерно так:
anonymous_enable=YES
anon_root=/srv/ftp
local_enable=YES
write_enable=YES
local_umask=022
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
anon_world_readable_only=YES
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
ascii_upload_enable=YES
listen=YES
а /etc/fstab так:
/home/arcanis/arch/repo                     /srv/ftp/repo       ext4    defaults,bind,ro            0 0

Замечания/предложения, как обычно, приветствуются
PGP 0x31361F01
arcanisrepo
arcanis
yaourt
больше не с нами. Рекомендуют Смотря на эту статью https://wiki.archlinux.org/index.php/AUR_helpers логичным выводом будет установить Aurman
что нужно изменить ?
С уважением, Бендальф.
Bendalf
логичным выводом будет установить Aurman
Немного странная логика, там автор обидчивый
Почти полная копия по использованию yay
https://repo.archlinuxcn.org/x86_64/yay-9.2.0-1-x86_64.pkg.tar.xz

P.s. вообще если просто нужны пакеты с аура то многие собранные можно скачать с этой репы https://repo.archlinuxcn.org/x86_64
Надо на yay, да, но мне лень переписывать рабочий код. aurman тоже утонул
PGP 0x31361F01
arcanisrepo
 
Зарегистрироваться или войдите чтобы оставить сообщение.