# Copyright 2026 Nadeŭka # Distributed under the terms of the GNU General Public License v2 # @ECLASS: firefox-bin.eclass # @MAINTAINER: # Nadeŭka # @SUPPORTED_EAPIS: 8 9 # @BLURB: Eclass for prebuilt Firefox-based browser bundles # @DESCRIPTION: # Installs a prebuilt Firefox-based browser bundle into /opt and adds a # launcher, policies, preferences, a desktop entry and program icons. # # Everything installed is named after FIREFOX_BIN_NAME. Setting FIREFOX_BIN_SLOT # before the inherit slots the bundle: SLOT is set to it and the names and the # installation directory gain the slot suffix and subdirectory. # # SRC_URI of the bundle is up to the ebuild, and so is signature verification: # src_unpack unpacks every tarball and skips signatures and language packs. # An ebuild without language packs can inherit verify-sig after this eclass to # get its src_unpack; one with them verifies the bundles in its own src_unpack # before calling firefox-bin_src_unpack. # Language packs are added by firefox-bin_set_l10n_src_uri. # # The version in the format of the Mozilla URIs is available right after the # inherit as FIREFOX_BIN_PV_MOZ, and FIREFOX_BIN_ISESR tells ESR builds apart, # which is handy for version-dependent patches as well. # @EXAMPLE: # EAPI=8 # SLOT=0 # inherit firefox-bin # # DESCRIPTION='Example Firefox-based browser' # HOMEPAGE=https://example.org # KEYWORDS='~amd64' # # SRC_URI=" # amd64? ( https://example.org/${PV}/browser-x86_64.tar.xz -> ${P}-amd64.tar.xz ) # arm64? ( https://example.org/${PV}/browser-aarch64.tar.xz -> ${P}-arm64.tar.xz ) # " if [[ ! -v _FIREFOX_BIN_ECLASS ]]; then _FIREFOX_BIN_ECLASS=1 case ${EAPI} in 8|9) ;; *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; esac # @ECLASS_VARIABLE: FIREFOX_BIN_ISESR # @PRE_INHERIT # @DEFAULT_UNSET # @DESCRIPTION: # Set to a non-empty value for the Extended Support Release, which makes # FIREFOX_BIN_PV_MOZ carry the esr suffix. : ${FIREFOX_BIN_ISESR:=} # @ECLASS_VARIABLE: FIREFOX_BIN_PV # @PRE_INHERIT # @DESCRIPTION: # Version of the Firefox the bundle is based on, in the Portage format # (157.0.1, 158.0_beta5, 160.0_alpha1_p20261011081412). PV unless set. : ${FIREFOX_BIN_PV:=${PV}} # @ECLASS_VARIABLE: FIREFOX_BIN_PV_MOZ # @OUTPUT_VARIABLE # @DESCRIPTION: # FIREFOX_BIN_PV in the format used by Mozilla in URIs: 157.0.1, 158.0b5, # 160.0a1 and 153.4.0esr, with the _p* snapshot suffix dropped. FIREFOX_BIN_PV_MOZ=${FIREFOX_BIN_PV%_p*} FIREFOX_BIN_PV_MOZ=${FIREFOX_BIN_PV_MOZ/_beta/b} FIREFOX_BIN_PV_MOZ=${FIREFOX_BIN_PV_MOZ/_alpha/a} if [[ -n ${FIREFOX_BIN_ISESR} ]]; then FIREFOX_BIN_PV_MOZ+=esr fi # @ECLASS_VARIABLE: FIREFOX_BIN_SLOT # @PRE_INHERIT # @DESCRIPTION: # Slot of the bundle. When set, SLOT is set to it and the launcher, the desktop # entry, the icons and the installation directory gain the slot suffix and # subdirectory: ${PN}-${FIREFOX_BIN_SLOT} and /opt/${PN}/${FIREFOX_BIN_SLOT}. # Otherwise the bundle is installed without a slot. : ${FIREFOX_BIN_SLOT:=} if [[ -n ${FIREFOX_BIN_SLOT} ]]; then SLOT=${FIREFOX_BIN_SLOT} fi # @ECLASS_VARIABLE: FIREFOX_BIN_NAME # @PRE_INHERIT # @DESCRIPTION: # Name of the launcher, the desktop entry and the icons, followed by the slot # when FIREFOX_BIN_SLOT is set. : ${FIREFOX_BIN_NAME:=${PN}${FIREFOX_BIN_SLOT:+-${FIREFOX_BIN_SLOT}}} # @ECLASS_VARIABLE: FIREFOX_BIN_D # @PRE_INHERIT # @DESCRIPTION: # Installation directory of the bundle, with the slot appended when # FIREFOX_BIN_SLOT is set. : ${FIREFOX_BIN_D:=/opt/${PN}${FIREFOX_BIN_SLOT:+/${FIREFOX_BIN_SLOT}}} # @ECLASS_VARIABLE: FIREFOX_BIN_EXEC # @PRE_INHERIT # @DESCRIPTION: # Executable to run inside the bundle. : ${FIREFOX_BIN_EXEC:=${PN}} # @ECLASS_VARIABLE: FIREFOX_BIN_WRAPPER_ARGS # @PRE_INHERIT # @DESCRIPTION: # Arguments passed to the browser by the launcher. : ${FIREFOX_BIN_WRAPPER_ARGS:=--name=${FIREFOX_BIN_NAME}} # @ECLASS_VARIABLE: FIREFOX_BIN_WMCLASS # @DESCRIPTION: # StartupWMClass value of the desktop entry. : ${FIREFOX_BIN_WMCLASS:=firefox} # @ECLASS_VARIABLE: FIREFOX_BIN_L10N # @DEFAULT_UNSET # @DESCRIPTION: # Array of Mozilla locales of the bundle. When set before # firefox-bin_set_l10n_src_uri is called, every locale gets an l10n_* USE # flag and a language pack distfile, and the enabled ones are installed by # src_install. # @ECLASS_VARIABLE: FIREFOX_BIN_L10N_URI # @DEFAULT_UNSET # @DESCRIPTION: # Language pack URI with @LANG@ standing for the locale. Required by # firefox-bin_set_l10n_src_uri. # @ECLASS_VARIABLE: FIREFOX_BIN_L10N_NOREGION # @DESCRIPTION: # Array of the locales whose USE flag drops the region: fy-NL gets l10n_fy. # The default covers the Mozilla locales with a single regional variant. To # extend it, append in the ebuild after the inherit; to replace it, set it # before the inherit. if [[ ! -v FIREFOX_BIN_L10N_NOREGION ]]; then FIREFOX_BIN_L10N_NOREGION=( fy-NL ga-IE gu-IN hi-IN hy-AM nb-NO ne-NP nn-NO pa-IN sv-SE ) fi inherit desktop linux-info multilib optfeature pax-utils xdg S=${WORKDIR}/${PN%%-*} LICENSE='MPL-2.0 GPL-2 LGPL-2.1' IUSE=wayland RESTRICT=strip QA_PREBUILT=${FIREFOX_BIN_D#/}/* RDEPEND=' || ( media-libs/libpulse media-sound/apulse ) >=app-accessibility/at-spi2-core-2.46.0:2 >=dev-libs/glib-2.26:2 >=media-libs/freetype-2.4.10 >=x11-libs/cairo-1.10[X] >=x11-libs/gtk+-3.11:3[X,wayland?] >=x11-libs/pango-1.22.0 media-libs/alsa-lib media-libs/fontconfig media-video/ffmpeg sys-apps/dbus sys-libs/glibc virtual/freedesktop-icon-theme x11-libs/gdk-pixbuf:2 x11-libs/libX11 x11-libs/libxcb x11-libs/libXcomposite x11-libs/libXcursor x11-libs/libXdamage x11-libs/libXext x11-libs/libXfixes x11-libs/libXi x11-libs/libXrandr x11-libs/libXrender ' BDEPEND=' app-arch/unzip app-misc/jq res-eclass/firefox-bin ' # @FUNCTION: _firefox-bin_l10n_flag # @USAGE: # @INTERNAL # @DESCRIPTION: # Sets REPLY to the name of the l10n USE flag (without the prefix) of the # given Mozilla locale. _firefox-bin_l10n_flag() { if has "$1" "${FIREFOX_BIN_L10N_NOREGION[@]}"; then REPLY=${1%%-*} else REPLY=$1 fi } # @FUNCTION: firefox-bin_set_l10n_src_uri # @DESCRIPTION: # Adds the language packs to SRC_URI and the matching l10n_* flags to IUSE, # one per locale of FIREFOX_BIN_L10N, from FIREFOX_BIN_L10N_URI. The packs are # stored as ${P}-.xpi. Intended to be called from the global scope # after SRC_URI of the bundle is set. firefox-bin_set_l10n_src_uri() { local lang [[ -n ${FIREFOX_BIN_L10N_URI} ]] || die "${FUNCNAME}: FIREFOX_BIN_L10N_URI is not set" for lang in "${FIREFOX_BIN_L10N[@]}"; do _firefox-bin_l10n_flag "${lang}" IUSE+=" l10n_${REPLY}" SRC_URI+=" l10n_${REPLY}? ( ${FIREFOX_BIN_L10N_URI//@LANG@/${lang}} -> ${P}-${lang}.xpi )" done } # @FUNCTION: firefox-bin_pkg_setup # @DESCRIPTION: # Warns when the kernel lacks seccomp, which DRM-protected content needs. firefox-bin_pkg_setup() { CONFIG_CHECK='~SECCOMP' WARNING_SECCOMP='CONFIG_SECCOMP not set! DRM-protected content will not work' linux-info_pkg_setup } # @FUNCTION: firefox-bin_src_unpack # @DESCRIPTION: # Unpacks the bundle tarballs and leaves the detached signatures (.asc, .sig) # and the language packs alone. Ebuilds with signatures verify them before # calling this. firefox-bin_src_unpack() { local f for f in ${A}; do case ${f} in *.asc|*.sig|*.xpi) ;; *) unpack "${f}" ;; esac done } # @FUNCTION: firefox-bin_src_install # @DESCRIPTION: # Installs the bundle, the launcher, the merged policies, the preferences, the # desktop entry, the icons, the enabled language packs and the dictionaries # symlink. firefox-bin_src_install() { local name=${FIREFOX_BIN_NAME} local dest=${FIREFOX_BIN_D} local res=${BROOT}/usr/share/res-ebuild/firefox-bin # bundle dodir "${dest}" cp -a . "${ED}${dest}" || die touch "${ED}${dest}"/is-packaged-app || die # launcher local exports=MOZ_APP_LAUNCHER apulse= if has_version -r 'media-sound/apulse[-sdk]'; then apulse="LD_LIBRARY_PATH=\"${EPREFIX}/usr/$(get_libdir)/apulse\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}\"" exports+=' LD_LIBRARY_PATH' fi newbin - "${name}" <<-EOF $(<"${res}"/firefox-bin) ${apulse} MOZ_APP_LAUNCHER='${EPREFIX}/usr/bin/${name}' export ${exports} exec '${dest}/${FIREFOX_BIN_EXEC}' ${FIREFOX_BIN_WRAPPER_ARGS} "\$@" EOF # policies and preferences local -a policies=( "${ED}${dest}"/distribution/policies.json "${res}"/policies.json ) [[ -f ${policies[0]} ]] || unset 'policies[0]' jq -s 'reduce .[] as $p ({}; . * $p)' "${policies[@]}" > "${T}"/policies.json || die insinto "${dest}"/distribution doins "${T}"/policies.json insinto "${dest}"/browser/defaults/pref doins "${res}"/maintainer-prefs.js # desktop entry sed \ -e "s|@NAME@|${DESCRIPTION}|g" \ -e "s|@PN@|${name}|g" \ -e "s|@EXEC@|${EPREFIX}/usr/bin/${name}|g" \ -e "s|@WMCLASS@|${FIREFOX_BIN_WMCLASS}|g" \ "${res}"/firefox-bin.desktop > "${T}"/${name}.desktop || die domenu "${T}"/${name}.desktop # icons local icon size for icon in browser/chrome/icons/default/default*.png; do [[ -f ${icon} ]] || die 'No program icons could be installed' size=${icon##*/default} newicon -s "${size%.png}" "${icon}" ${name}.png done # language packs if [[ -v FIREFOX_BIN_L10N ]]; then local lang xpi emid insinto "${dest}"/distribution/extensions for lang in "${FIREFOX_BIN_L10N[@]}"; do _firefox-bin_l10n_flag "${lang}" use "l10n_${REPLY}" || continue xpi=${DISTDIR}/${P}-${lang}.xpi emid=$(unzip -p "${xpi}" manifest.json | jq -r '.browser_specific_settings.gecko.id // .applications.gecko.id // empty') newins "${xpi}" "${emid:-langpack-${lang}@firefox.mozilla.org}".xpi done fi # dictionaries rm -rf "${ED}${dest}"/dictionaries || die dosym "${EPREFIX}"/usr/share/hunspell "${dest}"/dictionaries einstalldocs pax-mark m $(list-paxables "${ED}${dest}"/*) } # @FUNCTION: firefox-bin_pkg_postinst # @DESCRIPTION: # Updates the desktop databases and suggests optional runtime features. firefox-bin_pkg_postinst() { xdg_pkg_postinst optfeature 'desktop integration' sys-apps/xdg-desktop-portal optfeature 'fallback mouse cursor theme e.g. on WMs' gnome-base/gsettings-desktop-schemas optfeature 'location detection via Wi-Fi' net-misc/networkmanager optfeature 'pdf and web pages printing' net-print/cups optfeature 'speech synthesis (text-to-speech) support' app-accessibility/speech-dispatcher optfeature 'system spell checking dictionaries' app-text/hunspell if use wayland; then optfeature 'wayland screen sharing' media-video/pipewire fi } fi EXPORT_FUNCTIONS pkg_setup src_unpack src_install pkg_postinst