diff --git a/docs/DISTRO_COMPATIBILITY.md b/docs/DISTRO_COMPATIBILITY.md index 28fc5da..844a312 100644 --- a/docs/DISTRO_COMPATIBILITY.md +++ b/docs/DISTRO_COMPATIBILITY.md @@ -231,7 +231,7 @@ install the required system packages: ```bash sudo apt install python3-gi gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1 \ libgirepository1.0-dev libcairo2-dev portaudio19-dev python3-dev \ - python3-venv pkg-config xdotool wtype + python3-venv pkg-config xdotool wtype wl-clipboard xclip xsel ``` On Ubuntu 24.04+ or Pop!_OS, install `libgirepository-2.0-dev` if @@ -241,13 +241,13 @@ On Ubuntu 24.04+ or Pop!_OS, install `libgirepository-2.0-dev` if ```bash sudo dnf install python3-gobject gtk3 gtk3-devel libappindicator-gtk3 \ gobject-introspection-devel portaudio-devel python3-devel \ - python3-virtualenv pkg-config xdotool wtype + python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel ``` #### Arch Linux ```bash sudo pacman -S python-gobject gtk3 libappindicator gobject-introspection \ - python-cairo portaudio python-virtualenv pkg-config xdotool wtype + python-cairo portaudio python-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel ``` #### openSUSE @@ -257,7 +257,7 @@ PYVER=$(python3 -c 'import sys; print(f"python{sys.version_info.major}{sys.versi sudo zypper install "${PYVER}-gobject" "${PYVER}-gobject-cairo" gtk3 \ typelib-1_0-AyatanaAppIndicator3-0_1 libayatana-appindicator3-1 \ typelib-1_0-Notify-0_7 libnotify4 \ - portaudio-devel "${PYVER}-devel" "${PYVER}-virtualenv" pkg-config xdotool wtype + portaudio-devel "${PYVER}-devel" "${PYVER}-virtualenv" pkg-config xdotool wtype wl-clipboard xclip xsel ``` ### pip Installation Steps @@ -317,8 +317,8 @@ sudo zypper install "${PYVER}-gobject" "${PYVER}-gobject-cairo" gtk3 \ ### Why System Packages Are Required Vocalinux uses GTK3 for its GUI, AppIndicator/Ayatana for the system tray icon, -PortAudio for microphone capture, and tools such as `xdotool` or `wtype` for -text injection. These are system libraries and desktop tools that must be +PortAudio for microphone capture, and tools such as `xdotool`, `wtype`, and clipboard utilities (`wl-clipboard`, `xclip`, `xsel`) for +text injection and layout-independent Wayland paste fallback. These are system libraries and desktop tools that must be installed with your distribution's package manager. Python packages from PyPI can provide Python bindings, but they do not provide the underlying GTK typelibs, tray support, audio development libraries, or text injection binaries. @@ -361,16 +361,16 @@ Vocalinux requires text injection tools to work with X11 or Wayland: ### For Wayland - **IBus**: Recommended for KDE Plasma Wayland and generally the most reliable direct text input path - **wtype**: Recommended for wlroots-style Wayland compositors such as sway -- **ydotool**: Universal alternative that works with both X11 and Wayland, but requires `ydotoold` +- **ydotool**: Universal alternative that works with both X11 and Wayland, but requires `ydotoold`; Vocalinux uses clipboard paste with `wl-clipboard`, `xclip`, or `xsel` to avoid non-US layout scrambling - **xdotool**: May work via XWayland fallback ### Installation by Distribution ```bash # Ubuntu/Debian/Fedora/Arch/openSUSE -sudo apt install xdotool wtype # Ubuntu/Debian -sudo dnf install xdotool wtype # Fedora -sudo pacman -S xdotool wtype # Arch -sudo zypper install xdotool wtype # openSUSE +sudo apt install xdotool wtype wl-clipboard xclip xsel # Ubuntu/Debian +sudo dnf install xdotool wtype wl-clipboard xclip xsel # Fedora +sudo pacman -S xdotool wtype wl-clipboard xclip xsel # Arch +sudo zypper install xdotool wtype wl-clipboard xclip xsel # openSUSE ``` ## Manual Installation diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 7eccf8f..f1b2e36 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -41,7 +41,7 @@ sudo apt install -y \ python3-venv python3-dev python3-gi python3-gi-cairo \ gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1 \ libgirepository1.0-dev libcairo2-dev portaudio19-dev \ - pkg-config xdotool wtype + pkg-config xdotool wtype wl-clipboard xclip xsel python3 -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages source ~/.local/share/vocalinux-pypi/venv/bin/activate @@ -56,7 +56,7 @@ vocalinux sudo dnf install -y \ python3-virtualenv python3-devel python3-gobject gtk3 gtk3-devel \ libappindicator-gtk3 gobject-introspection-devel portaudio-devel \ - pkg-config xdotool wtype + pkg-config xdotool wtype wl-clipboard xclip xsel python3 -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages source ~/.local/share/vocalinux-pypi/venv/bin/activate @@ -70,7 +70,7 @@ vocalinux ```bash sudo pacman -S --needed \ python python-virtualenv python-gobject gtk3 libappindicator-gtk3 \ - gobject-introspection python-cairo portaudio pkg-config xdotool wtype + gobject-introspection python-cairo portaudio pkg-config xdotool wtype wl-clipboard xclip xsel python -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages source ~/.local/share/vocalinux-pypi/venv/bin/activate @@ -89,7 +89,7 @@ sudo zypper install -y \ typelib-1_0-AyatanaAppIndicator3-0_1 libayatana-appindicator3-1 \ typelib-1_0-Notify-0_7 libnotify4 \ gobject-introspection-devel portaudio-devel "${PYVER}-devel" \ - "${PYVER}-virtualenv" pkg-config xdotool wtype + "${PYVER}-virtualenv" pkg-config xdotool wtype wl-clipboard xclip xsel python3 -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages source ~/.local/share/vocalinux-pypi/venv/bin/activate @@ -302,7 +302,7 @@ sudo apt install -y gir1.2-ayatanaappindicator3-0.1 sudo apt install -y xdotool # For Wayland -sudo apt install -y wtype +sudo apt install -y wtype wl-clipboard xclip xsel ``` **Debian 11/12:** @@ -322,7 +322,7 @@ sudo apt install -y gir1.2-ayatanaappindicator3-0.1 sudo apt install -y xdotool # For Wayland -sudo apt install -y wtype +sudo apt install -y wtype wl-clipboard xclip xsel ``` **Debian 13+:** @@ -342,7 +342,7 @@ sudo apt install -y gir1.2-ayatanaappindicator3-0.1 sudo apt install -y xdotool # For Wayland -sudo apt install -y wtype +sudo apt install -y wtype wl-clipboard xclip xsel ``` **Fedora:** @@ -351,7 +351,7 @@ sudo dnf install -y \ python3-pip python3-devel python3-virtualenv \ python3-gobject gtk3 libappindicator-gtk3 \ gobject-introspection-devel portaudio-devel \ - wget curl unzip xdotool + wget curl unzip xdotool wtype wl-clipboard xclip xsel ``` **Arch Linux:** @@ -360,7 +360,7 @@ sudo pacman -S --noconfirm \ python-pip python-gobject gtk3 \ libappindicator-gtk3 gobject-introspection \ python-cairo portaudio python-virtualenv \ - wget curl unzip xdotool + wget curl unzip xdotool wtype wl-clipboard xclip xsel ``` **openSUSE Tumbleweed:** @@ -373,7 +373,7 @@ sudo zypper install -y \ gtk3 typelib-1_0-AyatanaAppIndicator3-0_1 libayatana-appindicator3-1 \ typelib-1_0-Notify-0_7 libnotify4 \ gobject-introspection-devel portaudio-devel pkg-config cmake \ - wget curl unzip xdotool wtype + wget curl unzip xdotool wtype wl-clipboard xclip xsel # Optional: only needed for whisper.cpp Vulkan GPU builds sudo zypper install -y vulkan-tools vulkan-devel shaderc @@ -593,8 +593,9 @@ For KDE Plasma Wayland: For Wayland: ```bash -sudo apt install wtype +sudo apt install wtype wl-clipboard xclip xsel # Test: wtype "hello" +# Clipboard fallback test: printf "bonjour" | xsel --clipboard --input ``` On KDE Plasma Wayland, `wtype` may fail because the compositor does not expose diff --git a/install.sh b/install.sh index 1c11653..0d07e38 100755 --- a/install.sh +++ b/install.sh @@ -1494,21 +1494,21 @@ install_system_dependencies() { # Debian install they are absent and cause CMake's bootstrap to fail (Hurdle 2 from # https://medium.com/@cslev/talking-to-my-linux-box-without-talking-to-the-cloud-vocalinux-on-debian-without-the-tears-10bf053ea21b). local PYWHISPERCPP_BUILD_DEPS="libssl-dev autoconf automake libtool patchelf" - local APT_PACKAGES_UBUNTU="python3-pip python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-appindicator3-0.1 gir1.2-ibus-1.0 $GI_DEV_PKG libcairo2-dev cmake python3-dev build-essential portaudio19-dev python3-venv pkg-config wget curl unzip vulkan-tools libvulkan-dev $VULKAN_SHADER_PKG xclip wl-clipboard $PYWHISPERCPP_BUILD_DEPS" - local APT_PACKAGES_DEBIAN_BASE="python3-pip python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ibus-1.0 libcairo2-dev cmake python3-dev build-essential portaudio19-dev python3-venv pkg-config wget curl unzip vulkan-tools libvulkan-dev $VULKAN_SHADER_PKG xclip wl-clipboard $PYWHISPERCPP_BUILD_DEPS" + local APT_PACKAGES_UBUNTU="python3-pip python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-appindicator3-0.1 gir1.2-ibus-1.0 $GI_DEV_PKG libcairo2-dev cmake python3-dev build-essential portaudio19-dev python3-venv pkg-config wget curl unzip vulkan-tools libvulkan-dev $VULKAN_SHADER_PKG xclip xsel wl-clipboard $PYWHISPERCPP_BUILD_DEPS" + local APT_PACKAGES_DEBIAN_BASE="python3-pip python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ibus-1.0 libcairo2-dev cmake python3-dev build-essential portaudio19-dev python3-venv pkg-config wget curl unzip vulkan-tools libvulkan-dev $VULKAN_SHADER_PKG xclip xsel wl-clipboard $PYWHISPERCPP_BUILD_DEPS" local APT_PACKAGES_DEBIAN_11_12="$APT_PACKAGES_DEBIAN_BASE libgirepository1.0-dev gir1.2-ayatanaappindicator3-0.1" local APT_PACKAGES_DEBIAN_13_PLUS="$APT_PACKAGES_DEBIAN_BASE libgirepository-2.0-dev gir1.2-ayatanaappindicator3-0.1" - local DNF_PACKAGES="python3-pip python3-gobject gtk3 libappindicator-gtk3 ibus-devel gobject-introspection-devel python3-devel portaudio-devel python3-virtualenv pkg-config cmake wget curl unzip vulkan-tools vulkan-loader-devel glslang xclip wl-clipboard" - local PACMAN_PACKAGES="python-pip python-gobject gtk3 libappindicator-gtk3 ibus gobject-introspection python-cairo portaudio python-virtualenv pkg-config cmake wget curl unzip base-devel vulkan-tools vulkan-headers glslang xclip wl-clipboard" - local ZYPPER_PACKAGES="gtk3 ibus-devel gobject-introspection-devel portaudio-devel pkg-config cmake wget curl unzip xclip wl-clipboard typelib-1_0-Notify-0_7 libnotify4" + local DNF_PACKAGES="python3-pip python3-gobject gtk3 libappindicator-gtk3 ibus-devel gobject-introspection-devel python3-devel portaudio-devel python3-virtualenv pkg-config cmake wget curl unzip vulkan-tools vulkan-loader-devel glslang xclip xsel wl-clipboard" + local PACMAN_PACKAGES="python-pip python-gobject gtk3 libappindicator-gtk3 ibus gobject-introspection python-cairo portaudio python-virtualenv pkg-config cmake wget curl unzip base-devel vulkan-tools vulkan-headers glslang xclip xsel wl-clipboard" + local ZYPPER_PACKAGES="gtk3 ibus-devel gobject-introspection-devel portaudio-devel pkg-config cmake wget curl unzip xclip xsel wl-clipboard typelib-1_0-Notify-0_7 libnotify4" # Gentoo uses Portage and different package naming convention - local EMERGE_PACKAGES="dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libayatana-appindicator media-libs/portaudio dev-lang/python:3.9 pkgconf cmake dev-util/glslang x11-misc/xclip gui-apps/wl-clipboard" + local EMERGE_PACKAGES="dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libayatana-appindicator media-libs/portaudio dev-lang/python:3.9 pkgconf cmake dev-util/glslang x11-misc/xclip x11-misc/xsel gui-apps/wl-clipboard" # Alpine Linux uses apk and has musl libc - local APK_PACKAGES="py3-gobject3 py3-pip gtk+3.0 py3-cairo portaudio-dev py3-virtualenv pkgconf cmake wget curl unzip glslang vulkan-tools xclip wl-clipboard" + local APK_PACKAGES="py3-gobject3 py3-pip gtk+3.0 py3-cairo portaudio-dev py3-virtualenv pkgconf cmake wget curl unzip glslang vulkan-tools xclip xsel wl-clipboard" # Void Linux uses xbps - local XBPS_PACKAGES="python3-pip python3-gobject gtk+3 libappindicator-gtk3 gobject-introspection portaudio-devel python3-devel pkg-config cmake wget curl unzip glslang Vulkan-Tools xclip wl-clipboard" + local XBPS_PACKAGES="python3-pip python3-gobject gtk+3 libappindicator-gtk3 gobject-introspection portaudio-devel python3-devel pkg-config cmake wget curl unzip glslang Vulkan-Tools xclip xsel wl-clipboard" # Solus uses eopkg - local EOPKG_PACKAGES="python3-pip python3-gobject gtk3 libappindicator gobject-introspection-devel portaudio-devel python3-virtualenv pkg-config cmake wget curl unzip glslang vulkan-tools xclip wl-clipboard" + local EOPKG_PACKAGES="python3-pip python3-gobject gtk3 libappindicator gobject-introspection-devel portaudio-devel python3-virtualenv pkg-config cmake wget curl unzip glslang vulkan-tools xclip xsel wl-clipboard" local MISSING_PACKAGES="" local INSTALL_CMD="" diff --git a/scripts/check-system-deps.sh b/scripts/check-system-deps.sh index 1c77ef9..82a474e 100755 --- a/scripts/check-system-deps.sh +++ b/scripts/check-system-deps.sh @@ -112,6 +112,27 @@ PY echo " ydotool not found (Wayland)" fi + echo "" + echo "Clipboard tools (recommended for Wayland layout-independent paste fallback):" + + if command -v wl-copy >/dev/null 2>&1; then + echo "✓ wl-copy (Wayland clipboard)" + else + echo " wl-copy not found (Wayland clipboard)" + fi + + if command -v xclip >/dev/null 2>&1; then + echo "✓ xclip (X11/XWayland clipboard)" + else + echo " xclip not found (X11/XWayland clipboard)" + fi + + if command -v xsel >/dev/null 2>&1; then + echo "✓ xsel (X11/XWayland clipboard fallback)" + else + echo " xsel not found (X11/XWayland clipboard fallback)" + fi + # Detect distribution for install hints echo "" DETECTED_DISTRO="unknown" @@ -137,17 +158,17 @@ PY if [[ "$DETECTED_DISTRO" == "ubuntu" || "$DETECTED_DISTRO_LIKE" == *"ubuntu"* || "$DETECTED_DISTRO" == "pop" || "$DETECTED_DISTRO" == "linuxmint" || "$DETECTED_DISTRO" == "elementary" || "$DETECTED_DISTRO" == "zorin" ]]; then echo "Ubuntu/Debian-based:" echo " sudo apt update" - echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 gir1.2-gdkpixbuf-2.0 portaudio19-dev python3-dev python3-venv pkg-config xdotool wtype" + echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 gir1.2-gdkpixbuf-2.0 portaudio19-dev python3-dev python3-venv pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "fedora" || "$DETECTED_DISTRO_LIKE" == *"fedora"* || "$DETECTED_DISTRO" == "rhel" || "$DETECTED_DISTRO" == "centos" || "$DETECTED_DISTRO" == "rocky" || "$DETECTED_DISTRO" == "almalinux" ]]; then echo "Fedora/RHEL-based:" - echo " sudo dnf install -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype" + echo " sudo dnf install -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "arch" || "$DETECTED_DISTRO_LIKE" == *"arch"* || "$DETECTED_DISTRO" == "manjaro" || "$DETECTED_DISTRO" == "endeavouros" ]]; then echo "Arch Linux-based:" - echo " sudo pacman -S --needed python-gobject gtk3 gobject-introspection portaudio python pkg-config xdotool wtype" + echo " sudo pacman -S --needed python-gobject gtk3 gobject-introspection portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "opensuse" || "$DETECTED_DISTRO_LIKE" == *"suse"* ]]; then echo "openSUSE:" echo " PYVER=\$(python3 -c 'import sys; print(f\"python{sys.version_info.major}{sys.version_info.minor}\")')" - echo " sudo zypper install -y \"\${PYVER}-gobject\" \"\${PYVER}-gobject-cairo\" gtk3 typelib-1_0-AyatanaAppIndicator3-0_1 libayatana-appindicator3-1 typelib-1_0-Notify-0_7 libnotify4 gobject-introspection-devel portaudio-devel \"\${PYVER}-devel\" \"\${PYVER}-virtualenv\" pkg-config xdotool wtype" + echo " sudo zypper install -y \"\${PYVER}-gobject\" \"\${PYVER}-gobject-cairo\" gtk3 typelib-1_0-AyatanaAppIndicator3-0_1 libayatana-appindicator3-1 typelib-1_0-Notify-0_7 libnotify4 gobject-introspection-devel portaudio-devel \"\${PYVER}-devel\" \"\${PYVER}-virtualenv\" pkg-config xdotool wtype wl-clipboard xclip xsel" echo " If \"\${PYVER}-virtualenv\" is unavailable, try \"\${PYVER}-venv\"." elif [[ "$DETECTED_DISTRO" == "gentoo" ]]; then echo "Gentoo:" @@ -157,26 +178,26 @@ PY echo " sudo apk add py3-gobject3 py3-pip gtk+3.0 py3-cairo portaudio-dev py3-virtualenv pkgconf xdotool wtype" elif [[ "$DETECTED_DISTRO" == "void" ]]; then echo "Void Linux:" - echo " sudo xbps-install -Sy python3-pip python3-gobject gtk+3 libappindicator gobject-introspection portaudio-devel python3-devel pkg-config xdotool wtype" + echo " sudo xbps-install -Sy python3-pip python3-gobject gtk+3 libappindicator gobject-introspection portaudio-devel python3-devel pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "solus" ]]; then echo "Solus:" - echo " sudo eopkg install python3-pip python3-gobject gtk3 libappindicator gobject-introspection-devel portaudio-devel python3-virtualenv pkg-config xdotool wtype" + echo " sudo eopkg install python3-pip python3-gobject gtk3 libappindicator gobject-introspection-devel portaudio-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "mageia" ]]; then echo "Mageia:" if command -v dnf >/dev/null 2>&1; then - echo " sudo dnf install -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype" + echo " sudo dnf install -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" else - echo " sudo urpmi -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype" + echo " sudo urpmi -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" fi else echo "Ubuntu/Debian-based:" - echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 portaudio19-dev python3-dev pkg-config xdotool wtype" + echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 portaudio19-dev python3-dev pkg-config xdotool wtype wl-clipboard xclip xsel" echo "" echo "Fedora/RHEL-based:" - echo " sudo dnf install -y python3-gobject gtk3-devel portaudio-devel python3-devel pkg-config xdotool wtype" + echo " sudo dnf install -y python3-gobject gtk3-devel portaudio-devel python3-devel pkg-config xdotool wtype wl-clipboard xclip xsel" echo "" echo "Arch Linux:" - echo " sudo pacman -S python-gobject gtk3 portaudio python pkg-config xdotool wtype" + echo " sudo pacman -S python-gobject gtk3 portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" fi echo "" diff --git a/scripts/distro-package-map.yaml b/scripts/distro-package-map.yaml index d396c09..eec215b 100644 --- a/scripts/distro-package-map.yaml +++ b/scripts/distro-package-map.yaml @@ -84,6 +84,18 @@ system_packages: void: ["xdotool"] solus: ["xdotool"] + # Clipboard tools used for layout-independent Wayland paste fallback + clipboard_tools: + ubuntu: ["wl-clipboard", "xclip", "xsel"] + debian: ["wl-clipboard", "xclip", "xsel"] + fedora: ["wl-clipboard", "xclip", "xsel"] + arch: ["wl-clipboard", "xclip", "xsel"] + opensuse: ["wl-clipboard", "xclip", "xsel"] + gentoo: ["gui-apps/wl-clipboard", "x11-misc/xclip", "x11-misc/xsel"] + alpine: ["wl-clipboard", "xclip", "xsel"] + void: ["wl-clipboard", "xclip", "xsel"] + solus: ["wl-clipboard", "xclip", "xsel"] + wtype: ubuntu: ["wtype"] debian: ["wtype"] diff --git a/tests/test_installer_cuda_diagnostics.py b/tests/test_installer_cuda_diagnostics.py index dd9109e..ef7c998 100644 --- a/tests/test_installer_cuda_diagnostics.py +++ b/tests/test_installer_cuda_diagnostics.py @@ -68,6 +68,28 @@ class InstallerCudaDiagnosticsTests(unittest.TestCase): self.assertIn("--replace-needed", source) self.assertIn("readelf not found", source) + def test_installer_includes_xsel_for_wayland_clipboard_fallback(self) -> None: + """Fresh installs should include xsel for ydotool's layout-safe paste path.""" + source = _installer_source() + + required_lines = [ + "local APT_PACKAGES_UBUNTU=", + "local APT_PACKAGES_DEBIAN_BASE=", + "local DNF_PACKAGES=", + "local PACMAN_PACKAGES=", + "local ZYPPER_PACKAGES=", + "local EMERGE_PACKAGES=", + "local APK_PACKAGES=", + "local XBPS_PACKAGES=", + "local EOPKG_PACKAGES=", + ] + + for name in required_lines: + line = next(line for line in source.splitlines() if name in line) + self.assertIn("xclip", line) + self.assertIn("xsel", line) + self.assertIn("wl-clipboard", line) + if __name__ == "__main__": unittest.main()