diff --git a/README.md b/README.md index 5c22ca4..1c047ac 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,16 @@ sudo dnf install openssh-clients sshpass freerdp tigervnc gnome-keyring Prerequisites: **Rust** (stable, via rustup), **Node 18+**, and the Tauri Linux system deps (`webkit2gtk-4.1`, `libappindicator`, etc). +On Arch, Debian/Ubuntu, Fedora, and openSUSE, install all runtime and build +dependencies interactively with: + +```bash +npm run deps:build +``` + +The AppImage installer runs the runtime-only dependency bootstrap automatically +and asks for confirmation before invoking the distribution package manager. + ```bash # Tauri system deps (Arch example) sudo pacman -S webkit2gtk-4.1 base-devel curl wget file openssl appmenu-gtk-module libappindicator-gtk3 librsvg diff --git a/docs/distribution.md b/docs/distribution.md index 50f59e6..54c9961 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -19,15 +19,28 @@ Expected release assets: ## Local AppImage Install +The installer first detects the Linux distribution and offers to install all +runtime dependencies through its official package manager. It does not make +system changes until the user confirms the package list. + ```bash chmod +x RemoteOpsX-x86_64.AppImage ./packaging/linux/install-appimage.sh ./RemoteOpsX-x86_64.AppImage ``` -On Arch, install FUSE 2 if the AppImage does not launch: +Set `REMOTEOPSX_SKIP_DEPENDENCIES=1` only when dependencies are already managed +by the host image or an administrator: + +```bash +REMOTEOPSX_SKIP_DEPENDENCIES=1 ./packaging/linux/install-appimage.sh ./RemoteOpsX-x86_64.AppImage +``` + +For source development, one command installs Rust, Tauri build requirements, +FreeRDP, and VNC development libraries on Arch, Debian/Ubuntu, Fedora, or +openSUSE: ```bash -sudo pacman -S fuse2 +npm run deps:build ``` ## Arch Package @@ -36,9 +49,8 @@ The starter `PKGBUILD` is in `packaging/arch/PKGBUILD`. Before publishing to AUR or a pacman repository: -1. Replace `OWNER` in `url` with the GitHub organization/user. -2. Copy `src-tauri/icons/128x128.png` to `packaging/arch/remoteopsx.png`. -3. Generate checksums: +1. Copy `src-tauri/icons/128x128.png` to `packaging/arch/remoteopsx.png`. +2. Generate checksums: ```bash cd packaging/arch diff --git a/package.json b/package.json index 0cf8621..d08fd56 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "tauri": "tauri", "app:dev": "tauri dev", "app:build": "tauri build", - "app:build:arch": "NO_STRIP=1 PKG_CONFIG_PATH=\"$PWD/scripts/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}\" tauri build" + "app:build:arch": "NO_STRIP=1 PKG_CONFIG_PATH=\"$PWD/scripts/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}\" tauri build", + "deps:runtime": "bash packaging/linux/bootstrap-dependencies.sh --runtime", + "deps:build": "bash packaging/linux/bootstrap-dependencies.sh --build" }, "dependencies": { "@tauri-apps/api": "^2.1.1", diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index 90d87ea..6181189 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -4,7 +4,7 @@ pkgver=0.1.0 pkgrel=1 pkgdesc="Linux remote operations cockpit for SSH, SFTP, RDP, VNC, health and runbooks" arch=('x86_64') -url="https://github.com/OWNER/remoteopsx" +url="https://github.com/darwvin-dev/RemoteOpsX" license=('MIT') depends=( 'fuse2' @@ -13,15 +13,16 @@ depends=( 'gtk3' 'libayatana-appindicator' 'librsvg' + 'sshpass' + 'curl' + 'freerdp' + 'tigervnc' + 'libsecret' ) optdepends=( - 'sshpass: password authentication for SSH/SFTP' - 'freerdp: RDP launcher' - 'tigervnc: VNC launcher' 'remmina: alternative VNC launcher' - 'gnome-keyring: Secret Service keyring backend' - 'kwallet: KDE keyring backend' - 'curl: legacy FTP support' + 'gnome-keyring: GNOME Secret Service provider' + 'kwallet: KDE Secret Service provider' ) provides=('remoteopsx') conflicts=('remoteopsx') diff --git a/packaging/linux/bootstrap-dependencies.sh b/packaging/linux/bootstrap-dependencies.sh new file mode 100644 index 0000000..53eef68 --- /dev/null +++ b/packaging/linux/bootstrap-dependencies.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +set -euo pipefail + +MODE="runtime" +ASSUME_YES=0 +DRY_RUN=0 + +usage() { + cat <<'EOF' +Install RemoteOpsX Linux dependencies using the host package manager. + +Usage: ./packaging/linux/bootstrap-dependencies.sh [--runtime|--build] [--yes] [--dry-run] + + --runtime Install dependencies needed by the packaged application (default) + --build Install runtime plus Rust/Tauri and native protocol build dependencies + --yes Skip the confirmation prompt + --dry-run Print the detected package manager and packages without changes +EOF +} + +for argument in "$@"; do + case "${argument}" in + --runtime) MODE="runtime" ;; + --build) MODE="build" ;; + --yes|-y) ASSUME_YES=1 ;; + --dry-run) DRY_RUN=1 ;; + --help|-h) usage; exit 0 ;; + *) echo "Unknown option: ${argument}" >&2; usage >&2; exit 2 ;; + esac +done + +if [[ "${EUID}" -eq 0 ]]; then + SUDO=() +elif command -v sudo >/dev/null 2>&1; then + SUDO=(sudo) +else + echo "sudo is required to install system packages." >&2 + exit 1 +fi + +manager="" +for candidate in pacman apt-get dnf zypper; do + if command -v "${candidate}" >/dev/null 2>&1; then + manager="${candidate}" + break + fi +done + +if [[ -z "${manager}" ]]; then + echo "Unsupported distribution: pacman, apt, dnf, or zypper was not found." >&2 + echo "See docs/distribution.md for the dependency list." >&2 + exit 1 +fi + +runtime_packages=() +build_packages=() +case "${manager}" in + pacman) + runtime_packages=(fuse2 openssh sshpass curl freerdp tigervnc libsecret) + build_packages=(base-devel rustup webkit2gtk-4.1 libayatana-appindicator librsvg libvncserver clang cmake pkgconf) + install_command=("${SUDO[@]}" pacman -S --needed) + [[ "${ASSUME_YES}" -eq 1 ]] && install_command+=(--noconfirm) + ;; + apt-get) + runtime_packages=(fuse3 openssh-client sshpass curl tigervnc-viewer gnome-keyring) + if apt-cache show freerdp3-x11 >/dev/null 2>&1; then + runtime_packages+=(freerdp3-x11) + build_packages+=(freerdp3-dev) + else + runtime_packages+=(freerdp2-x11) + build_packages+=(freerdp2-dev) + fi + if apt-cache show rustup >/dev/null 2>&1; then + build_packages+=(rustup) + else + build_packages+=(cargo rustc) + fi + build_packages+=(build-essential libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libssl-dev libvncserver-dev clang cmake pkg-config) + install_command=("${SUDO[@]}" apt-get install) + [[ "${ASSUME_YES}" -eq 1 ]] && install_command+=(-y) + ;; + dnf) + runtime_packages=(fuse openssh-clients sshpass curl freerdp tigervnc gnome-keyring) + build_packages=(gcc gcc-c++ make rust cargo webkit2gtk4.1-devel libappindicator-gtk3-devel librsvg2-devel openssl-devel freerdp-devel libvncserver-devel clang cmake pkgconf-pkg-config) + install_command=("${SUDO[@]}" dnf install) + [[ "${ASSUME_YES}" -eq 1 ]] && install_command+=(-y) + ;; + zypper) + runtime_packages=(fuse openssh sshpass curl freerdp tigervnc gnome-keyring) + build_packages=(gcc gcc-c++ make rust cargo webkit2gtk-4_1-devel libappindicator3-devel librsvg-devel libopenssl-devel freerdp-devel libvncserver-devel clang cmake pkg-config) + install_command=("${SUDO[@]}" zypper install) + [[ "${ASSUME_YES}" -eq 1 ]] && install_command+=(--non-interactive) + ;; +esac + +packages=("${runtime_packages[@]}") +if [[ "${MODE}" == "build" ]]; then + packages+=("${build_packages[@]}") +fi + +echo "RemoteOpsX will install ${MODE} dependencies with ${manager}:" +printf ' %s\n' "${packages[@]}" +if [[ "${DRY_RUN}" -eq 1 ]]; then + exit 0 +fi +if [[ "${ASSUME_YES}" -ne 1 ]]; then + read -r -p "Continue? [y/N] " reply + [[ "${reply}" =~ ^[Yy]$ ]] || { echo "Cancelled."; exit 0; } +fi + +if [[ "${manager}" == "apt-get" ]]; then + "${SUDO[@]}" apt-get update +fi +"${install_command[@]}" "${packages[@]}" + +if [[ "${MODE}" == "build" ]] && command -v rustup >/dev/null 2>&1; then + rustup toolchain install stable + rustup default stable +fi + +echo "RemoteOpsX ${MODE} dependencies are installed." diff --git a/packaging/linux/install-appimage.sh b/packaging/linux/install-appimage.sh index f43762e..000b905 100755 --- a/packaging/linux/install-appimage.sh +++ b/packaging/linux/install-appimage.sh @@ -7,6 +7,11 @@ INSTALL_DIR="${HOME}/.local/bin" APP_DIR="${HOME}/.local/share/applications" ICON_DIR="${HOME}/.local/share/icons/hicolor/128x128/apps" +if [[ "${REMOTEOPSX_SKIP_DEPENDENCIES:-0}" != "1" ]]; then + SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" + bash "${SCRIPT_DIR}/bootstrap-dependencies.sh" --runtime +fi + if [[ ! -f "${APPIMAGE}" ]]; then echo "AppImage not found: ${APPIMAGE}" >&2 echo "Usage: $0 path/to/RemoteOpsX-x86_64.AppImage" >&2 @@ -32,4 +37,3 @@ if command -v gtk-update-icon-cache >/dev/null 2>&1; then fi echo "Installed RemoteOpsX to ${INSTALL_DIR}/${APP_NAME}" -echo "If the AppImage does not start on Arch, install FUSE 2: sudo pacman -S fuse2" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 4ac2105..1f6bd73 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -47,7 +47,24 @@ ], "linux": { "deb": { - "depends": ["openssh-client"] + "depends": [ + "openssh-client", + "sshpass", + "curl", + "freerdp2-x11 | freerdp3-x11", + "tigervnc-viewer", + "gnome-keyring" + ] + }, + "rpm": { + "depends": [ + "openssh-clients", + "sshpass", + "curl", + "freerdp", + "tigervnc", + "gnome-keyring" + ] } } }