Установка мессенджера MAX в Calculate Linux из локального репозитория

Установка мессенджера MAX в Calculate Linux:

Создание ebuild MAX с актуальной версией:

Добавление нестабильных версий пакета:

#

echo "net-im/max ~amd64" >> /etc/portage/package.accept_keywords/custom

Создание директории ebuild MAX:

#

mkdir -p /var/calculate/repos/custom/net-im/max

Скрипт создает ebuild MAX с сохранением старых версий на 30 дней:

#

tee /usr/local/bin/generate-max-ebuild.sh <<'EOF'
#!/bin/bash
set -e

REPO="/var/calculate/repos/custom/net-im/max"
mkdir -p "$REPO"

# Получаем версию и URL
PKG_INFO=$(curl -sL "https://download.max.ru/linux/deb/dists/stable/main/binary-amd64/Packages" | awk '
    /^Package: max$/ { in_max=1 }
    in_max && /^Version: / { ver=$2 }
    in_max && /^Filename: / { fn=$2; exit }
    END { if(ver && fn) print ver "|" fn }
')

if [[ -z "$PKG_INFO" ]]; then
    echo "ERROR: Failed to fetch package info"
    exit 1
fi

VERSION="${PKG_INFO%|*}"
FILENAME="${PKG_INFO#*|}"
DEB_URL="https://download.max.ru/linux/deb/${FILENAME}"

echo "Latest version: ${VERSION}"
echo "DEB URL: ${DEB_URL}"

# Удаляем только ebuild'ы старше 30 дней (сохраняем последние версии для отката)
echo "Cleaning old ebuilds (older than 30 days)..."
cd "$REPO"
find . -name "max-*.ebuild" -mtime +30 -delete 2>/dev/null || true

# Проверяем, не существует ли уже ebuild с этой версией
if [[ -f "max-${VERSION}.ebuild" ]]; then
    echo "Ebuild max-${VERSION} already exists. No update needed."
    exit 0
fi

# Создаём новый ebuild
cat > "max-${VERSION}.ebuild" <<EOEBUILD
# Copyright 2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

EAPI=8

inherit unpacker xdg desktop

DESCRIPTION="Russian messenger and digital platform"
HOMEPAGE="https://max.ru"
SRC_URI="${DEB_URL} -> max-\${PV}.deb"

LICENSE="MAX-EULA"
SLOT="0"
KEYWORDS="~amd64"

RESTRICT="strip mirror"

DEPEND="
	x11-libs/gtk+:3
	x11-libs/libnotify
	dev-libs/nss
	x11-libs/libXtst
	app-accessibility/at-spi2-core
	app-crypt/libsecret
	x11-libs/libXScrnSaver
	x11-misc/xdg-utils
	sys-apps/util-linux
"
RDEPEND="\${DEPEND}"
BDEPEND=""

QA_PRESTRIPPED="
	/opt/max/bin/max
	/opt/max/bin/crashpad_handler
	/opt/max/lib64/*
	/opt/max/lib/*
"

S="\${WORKDIR}"

src_unpack() {
	unpack_deb max-\${PV}.deb
}

src_install() {
	mkdir -p "\${D}"/opt/max || die "mkdir /opt/max failed"
	
	if [[ -d usr/share/max ]]; then
		pushd usr/share/max >/dev/null || die
		tar cf - . | (cd "\${D}"/opt/max && tar xf -) || die "tar copy failed"
		popd >/dev/null || die
	else
		die "usr/share/max not found in deb"
	fi
	
	fperms +x /opt/max/bin/max
	fperms +x /opt/max/bin/crashpad_handler
	
	dosym ../../opt/max/bin/max /usr/bin/max
	
	if [[ -f usr/share/applications/max.desktop ]]; then
		sed -e 's|Exec=.*|Exec=/opt/max/bin/max|' \\
		    -e 's|Icon=.*|Icon=max|' \\
		    usr/share/applications/max.desktop > "\${T}"/max.desktop || die "sed failed"
		domenu "\${T}"/max.desktop
	fi
	
	if [[ -d usr/share/icons ]]; then
		insinto /usr/share
		doins -r usr/share/icons
	fi
	
	if [[ -d usr/share/pixmaps ]]; then
		insinto /usr/share
		doins -r usr/share/pixmaps
	fi
}

pkg_postinst() {
	xdg_desktop_database_update
	xdg_icon_cache_update
}

pkg_postrm() {
	xdg_desktop_database_update
	xdg_icon_cache_update
}
EOEBUILD

# Пересоздаём Manifest
rm -f Manifest
ebuild "max-${VERSION}.ebuild" manifest

echo ""
echo "=== Done ==="
echo "Created: max-${VERSION}.ebuild"
echo ""
echo "Available versions:"
ls -1 max-*.ebuild 2>/dev/null | sed 's/max-//;s/.ebuild//' | while read v; do
    echo "  =net-im/max-${v}"
done
echo ""
echo "Install latest: emerge -av =net-im/max-${VERSION}"
echo "Or update:      emerge -u net-im/max"
EOF

chmod +x /usr/local/bin/generate-max-ebuild.sh

Создать/обновить ebuild:

#

generate-max-ebuild.sh

Установить последнюю версию:

#

emerge -av net-im/max

ОБНОВЛЕНИЕ: Установка мессенджера MAX в Calculate Linux:

Создание ebuild MAX с актуальной версией:

Добавление нестабильных версий пакета:

#

echo "net-im/max ~amd64" >> /etc/portage/package.accept_keywords/custom

Создание директории ebuild MAX:

#

mkdir -p /var/calculate/repos/custom/net-im/max

В прошлой версии скрипта и создаваемые им ebuild не работали звонки, в новой вроде все работает. Так же добавлено подробное описание.

Скрипт создает ebuild MAX с сохранением семи предыдущих версий:

sudo tee /usr/local/bin/generate-max-ebuild.sh <<'SCRIPT'
#!/bin/bash
# Скрипт проверки и создания ebuild для мессенджера MAX
# Устанавливает в /opt/max, с поддержкой звонков

set -e

REPO_DIR="/var/calculate/repos/custom/net-im/max"
DISTFILES_DIR="/var/calculate/distfiles"
EBUILD_NAME="max"

# Цвета для вывода
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Очистка при прерывании
trap 'echo -e "\n${RED}✖ Прервано пользователем${NC}"; exit 1' INT TERM

echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║        Обновление ebuild для мессенджера MAX               ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""

# Показываем установленную версию
INSTALLED_VERSION=$(cat /var/db/pkg/net-im/max-*/PF 2>/dev/null | sed 's/net-im\/max-//' || echo "не установлен")
echo -e "${YELLOW}► Установленная версия:${NC} ${GREEN}${INSTALLED_VERSION}${NC}"
echo ""

# Получаем последнюю версию из репозитория Debian
echo -e "${YELLOW}► Проверка последней версии в репозитории...${NC}"
PKG_INFO=$(curl -sL "https://download.max.ru/linux/deb/dists/stable/main/binary-amd64/Packages" | awk '
    /^Package: max$/ { in_max=1 }
    in_max && /^Version: / { ver=$2 }
    in_max && /^Filename: / { fn=$2; exit }
    END { if(ver && fn) print ver "|" fn }
')

if [[ -z "$PKG_INFO" ]]; then
    echo -e "${RED}✖ Ошибка: не удалось получить информацию о пакете из репозитория${NC}"
    exit 1
fi

VERSION="${PKG_INFO%|*}"
FILENAME="${PKG_INFO#*|}"
DEB_URL="https://download.max.ru/linux/deb/${FILENAME}"

echo -e "${GREEN}✓ Найдена версия:${NC} ${VERSION}"
echo -e "${GREEN}✓ URL для скачивания:${NC} ${DEB_URL}"
echo ""

# Проверяем, не существует ли уже ebuild с этой версией
if [[ -f "${REPO_DIR}/${EBUILD_NAME}-${VERSION}.ebuild" ]]; then
    echo -e "${YELLOW}► Ebuild для версии ${VERSION} уже существует. Обновление не требуется.${NC}"
    echo ""
    echo -e "${GREEN}════════════════════════════════════════════════════════════${NC}"
    echo -e "${GREEN}  Установленная версия: ${INSTALLED_VERSION}${NC}"
    echo -e "${GREEN}  Актуальная версия:    ${VERSION}${NC}"
    echo -e "${GREEN}════════════════════════════════════════════════════════════${NC}"
    exit 0
fi

# Создаём директории
mkdir -p "${REPO_DIR}"
mkdir -p "${DISTFILES_DIR}"

DEB_FILE="${DISTFILES_DIR}/${EBUILD_NAME}-${VERSION}.deb"
DEB_VALID=0

# Проверяем существующий файл
if [[ -f "${DEB_FILE}" ]]; then
    echo -e "${YELLOW}► Найден существующий .deb файл, проверка целостности...${NC}"
    if ar t "${DEB_FILE}" > /dev/null 2>&1; then
        FILE_TYPE=$(file -b "${DEB_FILE}")
        if [[ "$FILE_TYPE" =~ "Debian binary package" ]]; then
            FILE_SIZE=$(du -h "${DEB_FILE}" | cut -f1)
            echo -e "${GREEN}✓ Файл целостен (${FILE_SIZE})${NC}"
            DEB_VALID=1
        else
            echo -e "${RED}✖ Файл повреждён (неверный тип: ${FILE_TYPE})${NC}"
            echo -e "${YELLOW}► Удаляем битый файл...${NC}"
            rm -f "${DEB_FILE}"
        fi
    else
        echo -e "${RED}✖ Файл повреждён (ar не может прочитать структуру)${NC}"
        echo -e "${YELLOW}► Удаляем битый файл...${NC}"
        rm -f "${DEB_FILE}"
    fi
fi

# Скачиваем, если файл не валиден
if [[ "${DEB_VALID}" -eq 0 ]]; then
    echo -e "${YELLOW}► Скачивание пакета...${NC}"
    echo ""
    
    # Скачиваем во временный файл, чтобы при обрыве не оставлять битый .deb
    TMP_FILE="${DEB_FILE}.tmp"
    rm -f "${TMP_FILE}"
    
    if curl -L --fail --progress-bar -o "${TMP_FILE}" "${DEB_URL}"; then
        # Проверяем скачанный временный файл
        echo ""
        echo -e "${YELLOW}► Проверка скачанного файла...${NC}"
        
        if ar t "${TMP_FILE}" > /dev/null 2>&1; then
            FILE_TYPE=$(file -b "${TMP_FILE}")
            if [[ "$FILE_TYPE" =~ "Debian binary package" ]]; then
                mv "${TMP_FILE}" "${DEB_FILE}"
                FILE_SIZE=$(du -h "${DEB_FILE}" | cut -f1)
                echo -e "${GREEN}✓ Пакет проверен и сохранён (${FILE_SIZE})${NC}"
                DEB_VALID=1
            else
                echo -e "${RED}✖ Ошибка: скачанный файл не является валидным .deb пакетом!${NC}"
                echo -e "${RED}  Тип файла: ${FILE_TYPE}${NC}"
                rm -f "${TMP_FILE}"
                exit 1
            fi
        else
            echo -e "${RED}✖ Ошибка: скачанный файл повреждён (ar не может прочитать структуру)${NC}"
            rm -f "${TMP_FILE}"
            exit 1
        fi
    else
        echo ""
        echo -e "${RED}✖ Ошибка: не удалось скачать пакет (обрыв соединения или недоступен сервер)${NC}"
        rm -f "${TMP_FILE}"
        exit 1
    fi
fi

# Двойная проверка перед продолжением
if [[ "${DEB_VALID}" -ne 1 ]]; then
    echo -e "${RED}✖ Критическая ошибка: .deb файл не прошёл проверку целостности${NC}"
    exit 1
fi

# Удаляем старые ebuild'ы, оставляем только 7 последних
echo ""
echo -e "${YELLOW}► Очистка старых ebuild (оставляем 7 последних)...${NC}"
cd "${REPO_DIR}"
ls -1t max-*.ebuild 2>/dev/null | tail -n +8 | while read old_ebuild; do
    echo -e "  ${RED}Удаляем:${NC} ${old_ebuild}"
    rm -f "${old_ebuild}" || true
done
echo -e "${GREEN}✓ Очистка завершена${NC}"
echo ""

# Создаём ebuild
echo -e "${YELLOW}► Создание ebuild...${NC}"
cat > "${REPO_DIR}/${EBUILD_NAME}-${VERSION}.ebuild" <<EOBUILD
# Copyright 2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

EAPI=8

inherit unpacker xdg desktop

DESCRIPTION="Russian messenger and digital platform"
HOMEPAGE="https://max.ru"
SRC_URI="${DEB_URL} -> max-\${PV}.deb"

LICENSE="MAX-EULA"
SLOT="0"
KEYWORDS="~amd64"

RESTRICT="strip mirror"

DEPEND="
	x11-libs/gtk+:3
	x11-libs/libnotify
	dev-libs/nss
	x11-libs/libXtst
	app-accessibility/at-spi2-core
	app-crypt/libsecret
	x11-libs/libXScrnSaver
	x11-misc/xdg-utils
	sys-apps/util-linux
	x11-libs/libXres
"
RDEPEND="\${DEPEND}
	net-libs/grpc
	dev-libs/openssl:0/3
	sys-libs/libcap
"
BDEPEND=""

QA_PRESTRIPPED="
	/opt/max/bin/max
	/opt/max/bin/crashpad_handler
	/opt/max/bin/max-service/bin/*
	/opt/max/bin/max-service/lib64/*
	/opt/max/lib64/*
	/opt/max/lib/*
"

S="\${WORKDIR}"

src_unpack() {
	unpack_deb max-\${PV}.deb
}

src_install() {
	# === Установка в /opt/max ===
	mkdir -p "\${D}"/opt/max || die
	cp -a usr/share/max/. "\${D}"/opt/max/ || die

	# Исполняемые файлы
	chmod +x "\${D}"/opt/max/bin/max
	chmod +x "\${D}"/opt/max/bin/crashpad_handler
	chmod +x "\${D}"/opt/max/bin/max-service/bin/max-service

	# === ФИКС ЗВОНКОВ: Удаляем конфликтующие системные библиотеки ===
	local max_libdir="\${D}/opt/max/bin/max-service/lib64"
	local sys_libs="
		libmount.so.1
		libpcre2-8.so.0
		libblkid.so.1
		libselinux.so.1
		libgio-2.0.so.0
		libglib-2.0.so.0
		libgobject-2.0.so.0
		libgmodule-2.0.so.0
	"
	for lib in \${sys_libs}; do
		if [[ -f "\${max_libdir}/\${lib}" ]]; then
			elog "Removing conflicting system library: \${lib}"
			rm -f "\${max_libdir}/\${lib}" || true
		fi
	done

	# === ФИКС ЗВОНКОВ: Симлинк libsystemd.so.0 ===
	if [[ -f "\${max_libdir}/libsystemd.so.0.23.0" ]]; then
		rm -f "\${max_libdir}"/libsystemd.so.0 "\${max_libdir}"/libsystemd.so.0.bak 2>/dev/null || true
		ln -s libsystemd.so.0.23.0 "\${max_libdir}"/libsystemd.so.0
	fi

	# === Обёртка /usr/bin/max ===
	rm -f "\${D}"/usr/bin/max 2>/dev/null || true
	mkdir -p "\${D}"/usr/bin || die

	cat > "\${D}"/usr/bin/max <<'WRAPPER'
#!/bin/bash
# Wrapper для MAX — запускает max-service перед основным приложением

MAX_SERVICE="/opt/max/bin/max-service/bin/max-service"
MAX_BIN="/opt/max/bin/max"

# Проверяем, запущен ли max-service
if ! pgrep -f "\$MAX_SERVICE" > /dev/null 2>&1; then
    # Запускаем max-service в фоне
    "\$MAX_SERVICE" &
    sleep 2
fi

# Запускаем основное приложение
exec "\$MAX_BIN" "\$@"
WRAPPER

	chmod +x "\${D}"/usr/bin/max

	# === Desktop-файл ===
	if [[ -f usr/share/applications/max.desktop ]]; then
		sed -e 's|Exec=.*|Exec=/usr/bin/max %U|' \
		    -e 's|Icon=.*|Icon=/opt/max/icons/max.png|' \
		    -e 's|DBusActivatable=.*|DBusActivatable=true|' \
		    -e 's|StartupWMClass=.*|StartupWMClass=max|' \
		    usr/share/applications/max.desktop > "\${T}"/max.desktop || die
		domenu "\${T}"/max.desktop
	fi

	# === Иконки ===
	if [[ -d usr/share/icons ]]; then
		insinto /usr/share
		doins -r usr/share/icons
	fi
	
	if [[ -d usr/share/pixmaps ]]; then
		insinto /usr/share
		doins -r usr/share/pixmaps
	fi
	
	# Симлинк на основную иконку в /opt/max/icons
	mkdir -p "\${D}"/opt/max/icons || die
	if [[ -f "\${D}"/usr/share/pixmaps/max.png ]]; then
		ln -s /usr/share/pixmaps/max.png "\${D}"/opt/max/icons/max.png 2>/dev/null || true
	elif [[ -f "\${D}"/usr/share/icons/hicolor/256x256/apps/max.png ]]; then
		ln -s /usr/share/icons/hicolor/256x256/apps/max.png "\${D}"/opt/max/icons/max.png 2>/dev/null || true
	fi

	# === D-Bus сервис ===
	insinto /usr/share/dbus-1/services
	cat > "\${T}"/ru.max.MAX.service <<'DBUS'
[D-BUS Service]
Name=ru.max.MAX
Exec=/usr/bin/max
DBUS
	doins "\${T}"/ru.max.MAX.service
}

pkg_preinst() {
	# Полная очистка старой установки
	if [[ -d "\${EROOT}/opt/max" ]]; then
		elog "Removing old max installation..."
		find "\${EROOT}/opt/max" -type f -exec chattr -i {} + 2>/dev/null || true
		rm -rf "\${EROOT}/opt/max" || true
	fi
	rm -f "\${EROOT}/usr/bin/max" 2>/dev/null || true
	rm -f "\${EROOT}/usr/share/applications/max.desktop" 2>/dev/null || true
}

pkg_postinst() {
	xdg_desktop_database_update
	xdg_icon_cache_update

	elog "MAX \${PV} установлен в /opt/max."
	elog ""
	elog "Возможности:"
	elog "  - Звонки работают (max-service запускается автоматически)"
	elog "  - Системные библиотеки приоритетнее bundled"
	elog ""
	elog "Запуск:"
	elog "  max"
	elog "  Или через иконку в меню приложений"
	elog ""
	elog "Если звонки не работают:"
	elog "  pgrep -f max-service"
	elog "  ldd /opt/max/bin/max-service/bin/max-service"
}

pkg_postrm() {
	xdg_desktop_database_update
	xdg_icon_cache_update
}
EOBUILD

# Пересоздаём Manifest ТОЛЬКО после успешной проверки .deb
echo -e "${YELLOW}► Обновление Manifest...${NC}"
cd "${REPO_DIR}"
rm -f Manifest
ebuild "${EBUILD_NAME}-${VERSION}.ebuild" manifest > /dev/null 2>&1
echo -e "${GREEN}✓ Manifest обновлён${NC}"
echo ""

# Итоговый вывод
echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║              Ebuild успешно создан!                        ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}► Информация:${NC}"
echo -e "  Файл: ${GREEN}${REPO_DIR}/${EBUILD_NAME}-${VERSION}.ebuild${NC}"
echo -e "  Версия: ${GREEN}${VERSION}${NC}"
echo ""
echo -e "${YELLOW}► Доступные версии:${NC}"
ls -1t max-*.ebuild 2>/dev/null | sed 's/max-//;s/.ebuild//' | while read v; do
    if [[ "$v" == "$VERSION" ]]; then
        echo -e "  ${GREEN}→ net-im/max-${v} (новая)${NC}"
    else
        echo -e "    net-im/max-${v}"
    fi
done
echo ""
echo -e "${YELLOW}► Установка/Обновление:${NC}"
echo -e "  ${BLUE}emerge -av =net-im/max-${VERSION}${NC}"
echo ""
SCRIPT

chmod +x /usr/local/bin/generate-max-ebuild.sh

Создать/обновить ebuild:

#

generate-max-ebuild.sh

Установить последнюю версию:

#

emerge -av net-im/max

Вот подробное описание скрипта update-max-ebuild.sh с полным раскрытием всех функций и технических деталей:


:clipboard: Описание скрипта generate-max-ebuild.sh

:magnifying_glass_tilted_left: Назначение

Скрипт автоматически проверяет наличие новых версий мессенджера MAX в официальном Debian-репозитории разработчика, скачивает .deb пакет, проверяет его целостность и генерирует Gentoo ebuild с интегрированными фиксами для корректной работы функции звонков.


:gear: Технические характеристики

Параметр Значение
Язык Bash
EAPI 8
Установочный префикс /opt/max (FHS-совместимый путь для сторонних бинарных пакетов)
Репозиторий /var/calculate/repos/custom/net-im/max
Distfiles /var/calculate/distfiles
Хранение версий Последние 7 ebuild (автоочистка старых)

:counterclockwise_arrows_button: Алгоритм работы скрипта

┌─────────────────────────────────────────────────────────────┐
│ 1. Определение установленной версии из /var/db/pkg          │
│ 2. Запрос Packages из репозитория download.max.ru           │
│ 3. Парсинг Version и Filename                               │
│ 4. Проверка: существует ли ebuild для этой версии?          │
│    ├── Да → Выход (обновление не требуется)                 │
│    └── Нет → Продолжаем                                     │
│ 5. Проверка/скачивание .deb с прогресс-баром                │
│ 6. Верификация целостности .deb (ar + file)                 │
│    ├── Битый → Удаление + повторная попытка                 │
│    └── Целый → Продолжаем                                   │
│ 7. Очистка старых ebuild (оставляем 7 последних)            │
│ 8. Генерация ebuild с интегрированными фиксами              │
│ 9. Создание Manifest (только после успешной проверки)       │
│ 10. Вывод итоговой информации                               │
└─────────────────────────────────────────────────────────────┘

:white_check_mark: Интегрированные фиксы для звонков

1. Удаление конфликтующих системных библиотек

Проблема: Пакет MAX содержит собственные копии системных библиотек в /opt/max/bin/max-service/lib64/. Бинарник max-service имеет жёстко прописанный RPATH=$ORIGIN/../lib64, что заставляет динамический загрузчик искать библиотеки сначала в этом каталоге.

Конфликт: Библиотеки из Debian Stable (на котором собран MAX) старше, чем в Gentoo. Например:

  • libmount.so.1 из MAX не содержит символа MOUNT_2_40, который требуется системной libgio-2.0.so.0
  • libpcre2-8.so.0 имеет несовместимую версионную информацию

Решение: При установке автоматически удаляются следующие библиотеки из max-service/lib64/:

libmount.so.1          # → используется системная из /usr/lib64
libpcre2-8.so.0        # → используется системная из /usr/lib64
libblkid.so.1          # → используется системная из /usr/lib64
libselinux.so.1        # → используется системная из /usr/lib64
libgio-2.0.so.0        # → используется системная из /usr/lib64
libglib-2.0.so.0       # → используется системная из /usr/lib64
libgobject-2.0.so.0    # → используется системная из /usr/lib64
libgmodule-2.0.so.0    # → используется системная из /usr/lib64

Механизм: ld-linux.so.2 после удаления библиотек из RPATH-каталога находит их в стандартных системных путях (/usr/lib64, /lib64), где расположены актуальные версии.


2. Симлинк libsystemd.so.0

Проблема: В пакете отсутствует символическая ссылка libsystemd.so.0 → libsystemd.so.0.23.0. Бинарник max-service слинкован с libsystemd.so.0, но динамический загрузчик не находит файл с таким именем.

Ошибка без фикса:

error while loading shared libraries: libsystemd.so.0: cannot open shared object file: No such file or directory

Решение: Автоматическое создание симлинка:

ln -s libsystemd.so.0.23.0 /opt/max/bin/max-service/lib64/libsystemd.so.0

3. Обёртка /usr/bin/max

Проблема: Для работы звонков необходимо, чтобы фоновый процесс max-service был запущен до открытия основного окна мессенджера. При стандартном запуске /opt/max/bin/max сервис не стартует автоматически.

Решение: Создаётся Bash-обёртка /usr/bin/max, которая:

  1. Проверяет наличие процесса max-service (pgrep -f)
  2. Если не запущен — стартует его в фоне (&) с задержкой 2 секунды для инициализации
  3. Запускает основной бинарник /opt/max/bin/max через exec (замещение процесса, без форка)

Код обёртки:

#!/bin/bash
MAX_SERVICE="/opt/max/bin/max-service/bin/max-service"
MAX_BIN="/opt/max/bin/max"

if ! pgrep -f "$MAX_SERVICE" > /dev/null 2>&1; then
    "$MAX_SERVICE" &
    sleep 2
fi
exec "$MAX_BIN" "$@"

4. Зависимость x11-libs/libXres

Проблема: max-service использует Qt6 XCB platform plugin, который требует библиотеку libXRes.so.1 (X11 Resource extension). В минимальных установках Gentoo эта библиотека может отсутствовать.

Ошибка без зависимости:

error while loading shared libraries: libXRes.so.1: cannot open shared object file: No such file or directory

Решение: Добавлена в DEPEND ebuild, что приводит к автоматической установке при emerge.


:file_folder: Установка в /opt/max

Обоснование: Согласно FHS (Filesystem Hierarchy Standard), каталог /opt предназначен для установки сторонних приложений, не входящих в базовую систему дистрибутива.

Структура установки:

/opt/max/
├── bin/
│   ├── max                          ← основной бинарник
│   ├── crashpad_handler             ← обработчик крашей
│   └── max-service/
│       ├── bin/
│       │   └── max-service          ← сервис звонков
│       └── lib64/                   ← библиотеки сервиса
├── lib64/                           ← основные библиотеки MAX
├── lib/                             ← дополнительные библиотеки
└── icons/
    └── max.png → /usr/share/pixmaps/max.png  ← симлинк

Преимущества /opt:

  • Изоляция от системных файлов
  • Простое удаление (rm -rf /opt/max)
  • Соответствие стандартам для проприетарного ПО

:desktop_computer: Desktop-файл в меню приложений

Исходный файл из .deb содержит пути Debian (Exec=/usr/share/max/bin/max, Icon=max), несовместимые с Gentoo.

Модификации ebuild:

Поле Было Стало
Exec /usr/share/max/bin/max /usr/bin/max %U
Icon max /opt/max/icons/max.png
DBusActivatable true
StartupWMClass max

Результат: Корректное отображение в меню приложений GNOME/KDE/XFCE с рабочей иконкой и запуском через обёртку.


:locked: Защита от повреждённых файлов

Этап Проверка Действие при ошибке
Существующий .deb ar t + file Удаление, повторное скачивание
Скачивание curl --fail Удаление .tmp, выход с ошибкой
Временный файл ar t + file Удаление .tmp, выход с ошибкой
Финальный файл DEB_VALID=1 Блокировка создания ebuild

Механизм атомарности: Скачивание ведётся в файл .tmp, который переименовывается в .deb только после успешной верификации. При обрыве соединения остаётся только битый .tmp, который удаляется.


:broom: Управление версиями

Автоочистка: При создании нового ebuild автоматически удаляются файлы старше 7-го по счёту (сортировка по времени модификации).

Пример хранения:

max-26.15.0.ebuild  ← удалится при создании новой
max-26.15.1.ebuild  ← удалится при создании новой
...
max-26.15.3.ebuild  ← сохранится
max-26.15.4.ebuild  ← текущая (новая)

:rocket: Использование

Запуск скрипта:

#

generate-max-ebuild.sh

Установка конкретной версии:

#

emerge -av =net-im/max-26.15.4

:bar_chart: Вывод скрипта (пример)

╔════════════════════════════════════════════════════════════╗
║        Обновление ebuild для мессенджера MAX               ║
╚════════════════════════════════════════════════════════════╝

► Установленная версия: 26.15.3

► Проверка последней версии в репозитории...
✓ Найдена версия: 26.15.4
✓ URL для скачивания: https://download.max.ru/linux/deb/...

► Скачивание пакета...
############################################## 100.0%

► Проверка скачанного файла...
✓ Пакет проверен и сохранён (252M)

► Очистка старых ebuild (оставляем 7 последних)...
  Удаляем: max-26.15.0.ebuild
✓ Очистка завершена

► Создание ebuild...
► Обновление Manifest...
✓ Manifest обновлён

╔════════════════════════════════════════════════════════════╗
║              Ebuild успешно создан!                        ║
╚════════════════════════════════════════════════════════════╝

► Доступные версии:
  → net-im/max-26.15.4 (новая)
    net-im/max-26.15.3

► Установка/Обновление:
  sudo emerge -av =net-im/max-26.15.4