#!/usr/bin/env bash set -euo pipefail ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) PREFIX=${PREFIX:-"$HOME/.local"} BUILD_DIR=${BUILD_DIR:-"$ROOT/build"} INSTALL_DEPS=0 ACTIVATE=0 ASSUME_YES=0 MINIMUM_RUST=1.87.0 usage() { cat <<'EOF' Usage: scripts/install.sh [options] Options: --deps Offer to install missing build dependencies --no-deps Do not install dependencies (default) --activate Activate Lumen in the running Plasma session --no-activate Build and install only (default) --yes, -y Assume yes for dependency installation prompts --help Show this help Environment: PREFIX Installation prefix (default: ~/.local) BUILD_DIR Build directory (default: ./build) LUMEN_STATE_DIR Activation backups and logs (default: PREFIX/share/lumen-wallpaper) EOF } log() { printf 'Lumen installer: %s\n' "$*" } fail() { printf 'Lumen installer: %s\n' "$*" >&2 exit 1 } while (($#)); do case "$1" in --deps) INSTALL_DEPS=1 ;; --no-deps) INSTALL_DEPS=0 ;; --activate) ACTIVATE=1 ;; --no-activate) ACTIVATE=0 ;; --yes|-y) ASSUME_YES=1 ;; --help) usage exit 0 ;; *) fail "Unknown option: $1" ;; esac shift done confirm() { local prompt=$1 local answer if ((ASSUME_YES)); then return 0 fi if [[ ! -t 0 ]]; then return 1 fi read -r -p "$prompt [y/N] " answer [[ $answer == y || $answer == Y || $answer == yes || $answer == YES ]] } rust_version_ok() { command -v rustc >/dev/null 2>&1 || return 1 local version version=$(rustc --version 2>/dev/null | awk '{print $2}') [[ -n $version ]] || return 1 printf '%s\n%s\n' "$MINIMUM_RUST" "$version" | sort -V -C } ecm_available() { local probe_dir probe_dir=$(mktemp -d "${TMPDIR:-/tmp}/lumen-ecm-probe.XXXXXX") if (cd "$probe_dir" && cmake --find-package \ -DNAME=ECM -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST \ >/dev/null 2>&1); then rm -rf -- "$probe_dir" return 0 fi rm -rf -- "$probe_dir" return 1 } dependencies_ready() { local command_name for command_name in cmake ninja c++ cargo rustc pkg-config; do command -v "$command_name" >/dev/null 2>&1 || return 1 done rust_version_ok || return 1 pkg-config --exists Qt6Core Qt6Gui Qt6Qml Qt6Quick || return 1 ecm_available || return 1 } run_as_root() { if ((EUID == 0)); then "$@" else command -v sudo >/dev/null 2>&1 || fail "sudo is required for system packages" sudo "$@" fi } install_dependencies() { if dependencies_ready; then log "Build dependencies are already available" return fi ((INSTALL_DEPS)) || return confirm "Install missing build dependencies with the system package manager?" \ || fail "Build dependencies are required; install them manually or rerun with --deps" if command -v dnf >/dev/null 2>&1; then run_as_root dnf install -y \ gcc-c++ cargo rustc cmake ninja-build extra-cmake-modules pkgconf-pkg-config curl \ qt6-qtbase-devel qt6-qtdeclarative-devel vulkan-loader-devel vulkan-headers \ kf6-kirigami plasma-workspace elif command -v apt-get >/dev/null 2>&1; then run_as_root apt-get update run_as_root apt-get install -y \ build-essential cargo rustc cmake ninja-build extra-cmake-modules pkg-config curl \ qt6-base-dev qt6-declarative-dev libvulkan-dev \ qml6-module-org-kde-kirigami plasma-workspace elif command -v pacman >/dev/null 2>&1; then run_as_root pacman -Sy --needed --noconfirm \ base-devel cargo cmake ninja extra-cmake-modules pkgconf curl \ qt6-base qt6-declarative vulkan-headers kirigami plasma-workspace else fail "Unsupported package manager. Install CMake, Ninja, a C++ compiler, Rust, Qt6, ECM, Vulkan, Kirigami, and Plasma Workspace manually" fi } ensure_rust() { if rust_version_ok; then return fi ((INSTALL_DEPS)) || return confirm "Rust $MINIMUM_RUST or newer is required. Install/update it with rustup in your home directory?" \ || fail "Rust $MINIMUM_RUST or newer is required" if command -v rustup >/dev/null 2>&1; then rustup toolchain install stable --profile minimal else command -v curl >/dev/null 2>&1 || fail "curl is required to download rustup" local rustup_script rustup_script=$(mktemp "${TMPDIR:-/tmp}/lumen-rustup.XXXXXX") curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o "$rustup_script" sh "$rustup_script" -y --profile minimal --no-modify-path rm -f -- "$rustup_script" fi export PATH="$HOME/.cargo/bin:$PATH" export RUSTUP_TOOLCHAIN=stable rust_version_ok || fail "The Rust toolchain is still older than $MINIMUM_RUST" } preflight() { local command_name for command_name in cmake ninja c++ cargo rustc pkg-config; do command -v "$command_name" >/dev/null 2>&1 \ || fail "Missing required command: $command_name" done rust_version_ok || fail "Rust $MINIMUM_RUST or newer is required" pkg-config --exists Qt6Core Qt6Gui Qt6Qml Qt6Quick \ || fail "Qt6 development packages are required" ecm_available || fail "Extra CMake Modules (ECM) are required" } install_dependencies ensure_rust preflight cmake -S "$ROOT" -B "$BUILD_DIR" -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$PREFIX" cmake --build "$BUILD_DIR" cmake --install "$BUILD_DIR" log "Installed Lumen Wallpaper to $PREFIX" if ((ACTIVATE)); then BUILD_DIR=${LUMEN_STATE_DIR:-"$PREFIX/share/lumen-wallpaper"} \ "$ROOT/scripts/activate.sh" else log "Activate it with scripts/activate.sh or choose Lumen Wallpaper in KDE settings" fi