# Copyright 2026 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 inherit desktop xdg MY_PN="${PN/-bin/}" DESCRIPTION="AFFiNE - Open-source knowledge base combining docs, whiteboards and databases" HOMEPAGE="https://affine.pro https://github.com/toeverything/AFFiNE" SRC_URI="https://github.com/toeverything/AFFiNE/releases/download/v${PV}/${MY_PN}-${PV}-stable-linux-x64.appimage" S="${WORKDIR}" LICENSE="MIT" SLOT="0" KEYWORDS="~amd64" RESTRICT="mirror strip bindist" RDEPEND=" >=app-accessibility/at-spi2-core-2.46.0:2 dev-libs/expat dev-libs/glib:2 dev-libs/nspr dev-libs/nss media-libs/alsa-lib media-libs/mesa sys-apps/dbus x11-libs/cairo x11-libs/gtk+:3 x11-libs/libdrm x11-libs/libX11 x11-libs/libxcb x11-libs/libXcomposite x11-libs/libXdamage x11-libs/libXext x11-libs/libXfixes x11-libs/libxkbcommon x11-libs/libXrandr x11-libs/pango x11-misc/xdg-utils " QA_PREBUILT="*" # Install path without -bin suffix (Gentoo convention) AFFINE_HOME="/opt/${MY_PN}" src_unpack() { cp "${DISTDIR}/${MY_PN}-${PV}-stable-linux-x64.appimage" "${S}/${MY_PN}.AppImage" || die chmod +x "${S}/${MY_PN}.AppImage" || die "${S}/${MY_PN}.AppImage" --appimage-extract >/dev/null 2>&1 || die "AppImage extraction failed" rm "${S}/${MY_PN}.AppImage" || die } src_prepare() { default } src_install() { # Use cp -r (like windsurf-bin) to preserve native permissions from AppImage. # doins -r strips all +x bits and requires complex permission restoration. mkdir -p "${ED}${AFFINE_HOME}" || die cp -rT squashfs-root "${ED}${AFFINE_HOME}" || die # Chrome sandbox: setuid root with restricted permissions (Electron requires this) fperms 4755 "${AFFINE_HOME}/usr/lib/affine-electron/chrome-sandbox" # Wrapper script → /usr/bin/affine dosym "${AFFINE_HOME}/usr/bin/AFFiNE" /usr/bin/${MY_PN} # Desktop file local desktop_file for desktop_file in squashfs-root/AFFiNE.desktop squashfs-root/affine-electron.desktop; do if [[ -f "${desktop_file}" ]]; then sed -i \ -e "s|Exec=.*|Exec=${MY_PN} %U|g" \ -e "s|Icon=.*|Icon=${MY_PN}|g" \ "${desktop_file}" || die newmenu "${desktop_file}" ${MY_PN}.desktop break fi done # Icons from hicolor theme local size icon_path for size in 16 32 48 64 128 256 512 1024; do for icon_path in \ squashfs-root/usr/share/icons/hicolor/${size}x${size}/apps/affine-electron.png; do if [[ -f "${icon_path}" ]]; then newicon -s ${size} "${icon_path}" ${MY_PN}.png break fi done done # Fallback pixmap (root icon may be a symlink, dereference it) if [[ -e squashfs-root/affine-electron.png ]]; then newicon "$(realpath squashfs-root/affine-electron.png)" ${MY_PN}.png fi } pkg_postinst() { xdg_pkg_postinst # Chrome sandbox setuid must be applied here (runs as root). # fperms in src_install runs as portage user → kernel silently drops setuid. chmod 4755 /opt/affine/usr/lib/affine-electron/chrome-sandbox 2>/dev/null elog "AFFiNE has been installed to ${AFFINE_HOME}" elog "" elog "To launch: ${MY_PN}" elog "" elog "Features:" elog " - Document editing with rich-text and block-based content" elog " - Whiteboard for visual thinking and planning" elog " - Local-first with optional cloud sync" elog " - Privacy-focused, open-source alternative to Notion" elog "" elog "Upstream: https://affine.pro" }