/
arch_linux
/
makepkg-wrapper
Обзор
Документация
Войти
/
arch_linux
/
makepkg-wrapper
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
makepkg-wrapper.sh
606 строк
19 KB
БАЛИЦКИЙ АЛЕКСАНДР НИКОЛАЕВИЧ
upload files
18 дек 2025, 10:44
18 дек 2025, 10:44
2487bb8
Код
Авторство
О чём код?
#!/usr/bin/env bash # makepkg-wrapper - улучшенная обёртка для makepkg # Автор: AI Assistant # Версия: 1.0.0 set -euo pipefail # Цвета для вывода readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly MAGENTA='\033[0;35m' readonly CYAN='\033[0;36m' readonly NC='\033[0m' # No Color # Конфигурация readonly CONFIG_FILE="${HOME}/.config/makepkg-wrapper.conf" readonly LOG_DIR="${HOME}/.cache/makepkg-wrapper/logs" readonly BUILD_DIR="${HOME}/.cache/makepkg-wrapper/builds" readonly VERSION="1.0.0" # Переменные состояния VERBOSE=false DRY_RUN=false LOG_FILE="" CURRENT_PACKAGE="" START_TIME="" # Основные функции утилиты print_banner() { cat << "EOF" __ ___ __ __ _ __ / |/ /___ _/ /_____ __/ /___ ____ ___ | | / /__ ________ / /|_/ / __ `/ //_/ _ \/ / / __ \/ __ `__ \ | | / / _ \/ ___/ _ \ / / / / /_/ / ,< / __/ / / /_/ / / / / / / | |/ / __/ / / __/ /_/ /_/\__,_/_/|_|\___/_/_/\____/_/ /_/ /_/ |___/\___/_/ \___/ EOF echo -e "${BLUE}Улучшенная обёртка для makepkg${NC}" echo -e "${YELLOW}Версия: ${VERSION}${NC}\n" } print_help() { cat << EOF Использование: $(basename "$0") [ОПЦИИ] [ПАКЕТ] Основные опции: -h, --help Показать эту справку -v, --version Показать версию -V, --verbose Подробный вывод -d, --dry-run Только показать, что будет сделано -c, --clean Очистить кеш и временные файлы -i, --install Собрать и установить пакет -s, --sync Обновить базу данных pacman перед сборкой -l, --log Сохранить лог в файл -p, --path ПУТЬ Путь к каталогу с PKGBUILD -j, --jobs ЧИСЛО Количество потоков для сборки --skip-checksum Пропустить проверку контрольных сумм --skip-pgp-check Пропустить проверку PGP подписей --no-deps Не проверять зависимости --as-deps Установить как зависимости --ignore-arch Игнорировать несовместимость архитектуры Примеры: $(basename "$0") -i # Собрать и установить пакет в текущем каталоге $(basename "$0") -p ~/aur/package # Собрать пакет из указанного каталога $(basename "$0") -c # Очистить кеш $(basename "$0") --dry-run -V # Подробный тестовый запуск Управление пакетами: search ТЕРМИН Поиск пакетов в AUR info ПАКЕТ Информация о пакете update Обновить все пакеты AUR (использует yay/paru если есть) list Список установленных пакетов AUR cleanup Удалить старые версии пакетов из кеша EOF } init_dirs() { mkdir -p "${LOG_DIR}" mkdir -p "${BUILD_DIR}" } load_config() { if [[ -f "${CONFIG_FILE}" ]]; then source "${CONFIG_FILE}" else # Конфигурация по умолчанию MAKEPKG_CONF="${HOME}/.makepkg.conf" MAX_KEEP_LOGS=10 MAX_KEEP_BUILDS=5 USE_COLOR=true NOTIFY_ON_COMPLETE=true DEFAULT_JOBS=$(nproc) fi } setup_logging() { if [[ -n "${LOG_FILE}" ]]; then exec > >(tee -a "${LOG_FILE}") 2>&1 fi } log_message() { local level="$1" local message="$2" local timestamp timestamp=$(date '+%Y-%m-%d %H:%M:%S') case "$level" in "INFO") echo -e "${GREEN}[INFO]${NC} ${timestamp}: ${message}" ;; "WARN") echo -e "${YELLOW}[WARN]${NC} ${timestamp}: ${message}" ;; "ERROR") echo -e "${RED}[ERROR]${NC} ${timestamp}: ${message}" ;; "DEBUG") if [[ "${VERBOSE}" == true ]]; then echo -e "${CYAN}[DEBUG]${NC} ${timestamp}: ${message}" fi ;; esac } check_dependencies() { local deps=("makepkg" "pacman") local missing_deps=() for dep in "${deps[@]}"; do if ! command -v "${dep}" >/dev/null 2>&1; then missing_deps+=("${dep}") fi done if [[ ${#missing_deps[@]} -gt 0 ]]; then log_message "ERROR" "Отсутствуют зависимости: ${missing_deps[*]}" log_message "INFO" "Установите их: sudo pacman -S ${missing_deps[*]}" exit 1 fi } find_pkgbuild() { local search_path="${1:-.}" if [[ -f "${search_path}/PKGBUILD" ]]; then echo "${search_path}/PKGBUILD" return 0 fi # Поиск в подкаталогах local found found=$(find "${search_path}" -maxdepth 2 -name "PKGBUILD" -type f | head -1) if [[ -n "${found}" ]]; then echo "${found}" return 0 fi return 1 } parse_pkgbuild() { local pkgbuild_file="$1" if [[ ! -f "${pkgbuild_file}" ]]; then log_message "ERROR" "Файл PKGBUILD не найден: ${pkgbuild_file}" return 1 fi # Извлекаем основную информацию из PKGBUILD pkgname=$(grep -E '^pkgname=' "${pkgbuild_file}" | head -1 | cut -d= -f2 | tr -d "'\"") pkgver=$(grep -E '^pkgver=' "${pkgbuild_file}" | head -1 | cut -d= -f2 | tr -d "'\"") pkgrel=$(grep -E '^pkgrel=' "${pkgbuild_file}" | head -1 | cut -d= -f2 | tr -d "'\"") if [[ -z "${pkgname}" ]]; then log_message "WARN" "Не удалось определить pkgname из PKGBUILD" pkgname="unknown" fi CURRENT_PACKAGE="${pkgname}" LOG_FILE="${LOG_DIR}/${pkgname}-$(date +%Y%m%d-%H%M%S).log" } show_package_info() { local pkgbuild_file="$1" log_message "INFO" "Анализ PKGBUILD: ${pkgbuild_file}" parse_pkgbuild "${pkgbuild_file}" echo -e "\n${CYAN}=== Информация о пакете ===${NC}" echo -e "${GREEN}Имя:${NC} ${pkgname}" echo -e "${GREEN}Версия:${NC} ${pkgver:-неизвестно}" echo -e "${GREEN}Релиз:${NC} ${pkgrel:-неизвестно}" # Показываем зависимости echo -e "\n${CYAN}=== Зависимости ===${NC}" local deps_types=("depends" "makedepends" "checkdepends") for dep_type in "${deps_types[@]}"; do local deps deps=$(grep -E "^${dep_type}=" "${pkgbuild_file}" | sed 's/^[^=]*=//' | tr -d "'\"()" | sed 's/ /\n/g' | grep -v '^$') if [[ -n "${deps}" ]]; then echo -e "${YELLOW}${dep_type}:${NC}" echo "${deps}" | sed 's/^/ /' fi done # Показываем исходники echo -e "\n${CYAN}=== Источники ===${NC}" local sources sources=$(grep -E '^source=' "${pkgbuild_file}" | sed 's/^[^=]*=//' | tr -d "'\"" | sed 's/ /\n/g' | grep -v '^$') if [[ -n "${sources}" ]]; then echo "${sources}" | head -5 | sed 's/^/ /' if [[ $(echo "${sources}" | wc -l) -gt 5 ]]; then echo " ... и ещё $(($(echo "${sources}" | wc -l) - 5))" fi fi } build_package() { local pkgbuild_dir="$1" local makepkg_args=("$@") log_message "INFO" "Начало сборки пакета в ${pkgbuild_dir}" START_TIME=$(date +%s) pushd "${pkgbuild_dir}" > /dev/null || { log_message "ERROR" "Не удалось перейти в каталог ${pkgbuild_dir}" return 1 } # Показываем информацию о пакете show_package_info "./PKGBUILD" echo -e "\n${CYAN}=== Начало сборки ===${NC}" if [[ "${DRY_RUN}" == true ]]; then log_message "INFO" "Режим dry-run, выполнение команд:" echo "cd ${pkgbuild_dir}" echo "makepkg ${makepkg_args[*]}" popd > /dev/null return 0 fi # Запускаем makepkg if [[ "${VERBOSE}" == true ]]; then if command -v makepkg >/dev/null 2>&1; then makepkg "${makepkg_args[@]}" else /usr/bin/makepkg "${makepkg_args[@]}" fi else if command -v makepkg >/dev/null 2>&1; then makepkg "${makepkg_args[@]}" 2>&1 | grep -E --color=auto '(==>|error|warning|ERROR|WARN)' else /usr/bin/makepkg "${makepkg_args[@]}" 2>&1 | grep -E --color=auto '(==>|error|warning|ERROR|WARN)' fi fi local exit_code=$? popd > /dev/null END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) if [[ ${exit_code} -eq 0 ]]; then log_message "INFO" "Сборка завершена успешно за ${DURATION} секунд" # Найти созданный пакет local pkg_file pkg_file=$(find "${pkgbuild_dir}" -name "*.pkg.tar.zst" -o -name "*.pkg.tar.xz" | head -1) if [[ -f "${pkg_file}" ]]; then echo -e "\n${GREEN}✓ Пакет создан:${NC} $(basename "${pkg_file}")" echo -e "${GREEN} Размер:${NC} $(du -h "${pkg_file}" | cut -f1)" echo -e "${GREEN} Путь:${NC} ${pkg_file}" fi # Уведомление if [[ "${NOTIFY_ON_COMPLETE:-true}" == true ]] && command -v notify-send >/dev/null 2>&1; then notify-send "Сборка пакета завершена" "${pkgname} успешно собран за ${DURATION} секунд" fi else log_message "ERROR" "Сборка завершилась с ошибкой (код: ${exit_code})" log_message "INFO" "Подробности в лог-файле: ${LOG_FILE}" fi return ${exit_code} } install_package() { local pkgbuild_dir="$1" shift log_message "INFO" "Сборка и установка пакета" # Сначала собираем if ! build_package "${pkgbuild_dir}" "$@"; then return 1 } # Находим созданный пакет local pkg_file pkg_file=$(find "${pkgbuild_dir}" -name "*.pkg.tar.zst" -o -name "*.pkg.tar.xz" | head -1) if [[ ! -f "${pkg_file}" ]]; then log_message "ERROR" "Файл пакета не найден" return 1 fi echo -e "\n${CYAN}=== Установка пакета ===${NC}" if [[ "${DRY_RUN}" == true ]]; then log_message "INFO" "Режим dry-run, установка не выполняется" echo "sudo pacman -U \"${pkg_file}\"" return 0 fi # Устанавливаем пакет if sudo pacman -U "${pkg_file}"; then log_message "INFO" "Пакет успешно установлен" return 0 else log_message "ERROR" "Ошибка при установке пакета" return 1 fi } clean_cache() { echo -e "${YELLOW}Очистка кеша...${NC}" if [[ -d "${LOG_DIR}" ]]; then local log_count log_count=$(find "${LOG_DIR}" -type f | wc -l) if [[ ${log_count} -gt 0 ]]; then rm -rf "${LOG_DIR:?}"/* echo -e "${GREEN}✓ Удалено лог-файлов:${NC} ${log_count}" fi fi if [[ -d "${BUILD_DIR}" ]]; then local build_count build_count=$(find "${BUILD_DIR}" -type f -name "*.pkg.*" | wc -l) if [[ ${build_count} -gt 0 ]]; then rm -rf "${BUILD_DIR:?}"/* echo -e "${GREEN}✓ Удалено файлов сборки:${NC} ${build_count}" fi fi # Также очищаем кеш makepkg if [[ -d ~/.cache/makepkg ]]; then echo -e "${GREEN}✓ Очищен кеш makepkg${NC}" rm -rf ~/.cache/makepkg/* fi echo -e "${GREEN}Очистка завершена${NC}" } search_aur() { local query="$1" if ! command -v yay >/dev/null 2>&1 && ! command -v paru >/dev/null 2>&1; then log_message "WARN" "Для поиска в AUR установите yay или paru" log_message "INFO" "Можно установить: sudo pacman -S --needed git base-devel && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si" return 1 fi echo -e "${CYAN}=== Поиск в AUR: '${query}' ===${NC}" if command -v yay >/dev/null 2>&1; then yay -Ss "${query}" --aur elif command -v paru >/dev/null 2>&1; then paru -Ss "${query}" --aur fi } update_aur_packages() { if ! command -v yay >/dev/null 2>&1 && ! command -v paru >/dev/null 2>&1; then log_message "ERROR" "Для обновления AUR пакетов установите yay или paru" return 1 fi echo -e "${CYAN}=== Обновление AUR пакетов ===${NC}" if command -v yay >/dev/null 2>&1; then yay -Syu --aur elif command -v paru >/dev/null 2>&1; then paru -Syu --aur fi } list_installed_aur() { echo -e "${CYAN}=== Установленные AUR пакеты ===${NC}" if command -v yay >/dev/null 2>&1; then yay -Qm elif command -v paru >/dev/null 2>&1; then paru -Qm else # Альтернативный способ pacman -Qm | while read -r line; do pkgname=$(echo "${line}" | cut -d' ' -f1) if [[ ! ${pkgname} == "yay" ]] && [[ ! ${pkgname} == "paru" ]]; then echo "${line}" fi done fi } cleanup_old_packages() { echo -e "${CYAN}=== Очистка старых версий пакетов ===${NC}" if [[ -d ~/.cache/pacman/pkg ]]; then echo "Очистка кеша pacman..." sudo paccache -r fi if command -v yay >/dev/null 2>&1; then echo "Очистка кеша yay..." yay -Sc --aur elif command -v paru >/dev/null 2>&1; then echo "Очистка кеша paru..." paru -Sc --aur fi echo -e "${GREEN}Очистка завершена${NC}" } main() { # Парсинг аргументов local pkgbuild_path="." local action="build" local makepkg_args=() local custom_search_path="" # Показывать баннер только для основных действий if [[ $# -eq 0 ]] || [[ "$1" =~ ^-h|--help|^-v|--version ]]; then print_banner fi while [[ $# -gt 0 ]]; do case "$1" in -h|--help) print_help exit 0 ;; -v|--version) echo "makepkg-wrapper версия ${VERSION}" exit 0 ;; -V|--verbose) VERBOSE=true makepkg_args+=("$1") shift ;; -d|--dry-run) DRY_RUN=true shift ;; -c|--clean) action="clean" shift ;; -i|--install) action="install" shift ;; -s|--sync) makepkg_args+=("-s") shift ;; -l|--log) LOG_FILE="${LOG_DIR}/makepkg-$(date +%Y%m%d-%H%M%S).log" shift ;; -p|--path) custom_search_path="$2" pkgbuild_path="$2" shift 2 ;; -j|--jobs) makepkg_args+=("-j$2") shift 2 ;; --skip-checksum|--skip-pgp-check|--no-deps|--as-deps|--ignore-arch) makepkg_args+=("$1") shift ;; search) action="search" shift if [[ $# -gt 0 ]]; then query="$*" break else log_message "ERROR" "Укажите поисковый запрос" exit 1 fi ;; info) action="info" shift if [[ $# -gt 0 ]]; then query="$*" break else log_message "ERROR" "Укажите имя пакета" exit 1 fi ;; update) action="update" shift ;; list) action="list" shift ;; cleanup) action="cleanup" shift ;; -*) log_message "WARN" "Неизвестный аргумент: $1" shift ;; *) # Если это не опция, считаем это путем к PKGBUILD if [[ -d "$1" ]] || [[ -f "$1" ]]; then pkgbuild_path="$1" else # Или именем пакета для поиска query="$1" action="search" fi shift ;; esac done # Инициализация init_dirs load_config setup_logging check_dependencies # Выполнение действия case "${action}" in build) local pkgbuild_file if pkgbuild_file=$(find_pkgbuild "${pkgbuild_path}"); then build_package "$(dirname "${pkgbuild_file}")" "${makepkg_args[@]}" else log_message "ERROR" "PKGBUILD не найден в ${pkgbuild_path}" exit 1 fi ;; install) local pkgbuild_file if pkgbuild_file=$(find_pkgbuild "${pkgbuild_path}"); then install_package "$(dirname "${pkgbuild_file}")" "${makepkg_args[@]}" else log_message "ERROR" "PKGBUILD не найден в ${pkgbuild_path}" exit 1 fi ;; clean) clean_cache ;; search) search_aur "${query:-}" ;; info) if [[ -f "${query}/PKGBUILD" ]]; then show_package_info "${query}/PKGBUILD" elif [[ -f "PKGBUILD" ]]; then show_package_info "PKGBUILD" else log_message "ERROR" "PKGBUILD не найден" exit 1 fi ;; update) update_aur_packages ;; list) list_installed_aur ;; cleanup) cleanup_old_packages ;; esac } # Запуск основной функции if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi