From efa831bd0b440d7604ef71248e32d0238e2fdfe8 Mon Sep 17 00:00:00 2001 From: Khoa Vo Date: Mon, 29 Jun 2026 20:45:48 +0700 Subject: [PATCH] add installation and packaging scripts --- install.sh | 268 +++++++++++++++++++++++++++++++++++++ packaging/99-vietc.rules | 3 + packaging/build-tarball.sh | 60 +++++++++ packaging/deb/build-deb.sh | 15 ++- 4 files changed, 345 insertions(+), 1 deletion(-) create mode 100755 install.sh create mode 100644 packaging/99-vietc.rules create mode 100755 packaging/build-tarball.sh diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..22101a2 --- /dev/null +++ b/install.sh @@ -0,0 +1,268 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT +# Viet+ — Vietnamese Input Method Installer +set -euo pipefail + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0;69m' # No Color +NC='\033[0m' + +echo -e "${BLUE}=== Viet+ Installation Script ===${NC}" + +# Check for root privilege requirement +check_root() { + if [ "$EUID" -ne 0 ]; then + echo -e "${RED}Error: This script must be run as root (or with sudo) to install system files and update permissions.${NC}" + echo -e "Please re-run as: ${YELLOW}sudo $0${NC}" + exit 1 + fi +} + +# Detect distribution +detect_distro() { + if [ -f /etc/os-release ]; then + . /etc/os-release + DISTRO=$ID + else + echo -e "${RED}Error: Cannot detect Linux distribution (/etc/os-release missing).${NC}" + exit 1 + fi + echo -e "Detected OS: ${GREEN}${DISTRO}${NC}" +} + +# Install dependencies using package manager +install_dependencies() { + local mode=$1 # "build" or "run" + echo -e "Installing ${mode} dependencies..." + + case "$DISTRO" in + ubuntu|debian|raspbian|pop|mint|neon) + apt-get update -y + if [ "$mode" = "build" ]; then + apt-get install -y build-essential pkg-config libx11-dev libxtst-dev libdbus-1-dev libevdev-dev + fi + apt-get install -y libevdev2 libdbus-1-3 libx11-6 libxtst6 xclip wl-clipboard + ;; + fedora|rhel|centos) + if [ "$mode" = "build" ]; then + dnf install -y gcc pkgconfig libX11-devel libXtst-devel dbus-devel libevdev-devel + fi + dnf install -y libevdev libX11 libXtst dbus-libs xclip wl-clipboard + ;; + arch|manjaro|arco) + if [ "$mode" = "build" ]; then + pacman -Sy --needed --noconfirm base-devel pkgconf libx11 libxtst dbus libevdev + fi + pacman -Sy --needed --noconfirm libevdev libx11 libxtst dbus xclip wl-clipboard + ;; + *) + echo -e "${YELLOW}Warning: Unsupported distribution '${DISTRO}'. Please make sure you have the following packages installed manually:${NC}" + echo -e " - libevdev, libdbus-1, libx11, libxtst, xclip, wl-clipboard" + if [ "$mode" = "build" ]; then + echo -e " - gcc, pkg-config, and development headers for the above libraries." + fi + ;; + esac +} + +# Check for Rust compiler (needed only for source build) +check_rust() { + if ! command -v cargo >/dev/null 2>&1; then + echo -e "${YELLOW}Rust toolchain not found.${NC}" + read -p "Would you like to install Rust toolchain now? [Y/n] " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "${RED}Error: Cargo is required to build from source.${NC}" + exit 1 + fi + echo "Installing Rust via rustup.rs..." + # Run rustup installer as the original non-root user if SUDO_USER is set + local user_cmd="" + if [ -n "${SUDO_USER:-}" ]; then + su - "$SUDO_USER" -c "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y" + # Add to PATH for this script session + export PATH="/home/$SUDO_USER/.cargo/bin:$PATH" + else + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + export PATH="$HOME/.cargo/bin:$PATH" + fi + fi + echo -e "Rust version: ${GREEN}$(rustc --version)${NC}" +} + +# Determine if we are installing from source tree or prebuilt binaries +check_root # Need root to perform OS checks and dependencies install +detect_distro + +SOURCE_DIR="" +if [ -f "./Cargo.toml" ] && [ -d "./engine" ] && [ -d "./ui" ]; then + SOURCE_DIR=$(pwd) + echo -e "Status: Running from ${GREEN}Source Tree${NC}" +else + echo -e "Status: Running from ${GREEN}Release Package${NC}" +fi + +# 1. Compile or Stage Binaries +if [ -n "$SOURCE_DIR" ]; then + install_dependencies "build" + check_rust + + echo -e "=== Compiling Viet+ ===" + # Build core components + cargo build --release + # Build UI + (cd ui && cargo build --release) + # Compile C helper + gcc -O2 -o target/release/vietc-xrecord packaging/deb/vietc-xrecord.c -lX11 -lXtst + + BIN_DAEMON="target/release/vietc" + BIN_CLI="target/release/vietc-cli" + BIN_UINPUTD="target/release/vietc-uinputd" + BIN_TRAY="ui/target/release/vietc-tray" + BIN_XRECORD="target/release/vietc-xrecord" + + FILE_RULES="packaging/99-vietc.rules" + FILE_DESKTOP="packaging/deb/vietc.desktop" + FILE_CONFIG="vietc.toml" + DIR_ICONS="packaging/icons" +else + # Install from prebuilt release folder + install_dependencies "run" + + BIN_DAEMON="bin/vietc-daemon" + BIN_CLI="bin/vietc-cli" + BIN_UINPUTD="bin/vietc-uinputd" + BIN_TRAY="bin/vietc-tray" + BIN_XRECORD="bin/vietc-xrecord" + + FILE_RULES="udev/99-vietc.rules" + FILE_DESKTOP="desktop/vietc.desktop" + FILE_CONFIG="config/config.toml" + DIR_ICONS="icons" + + # Validation + if [ ! -f "$BIN_DAEMON" ] && [ -f "bin/vietc" ]; then + BIN_DAEMON="bin/vietc" # Fallback if not renamed in build + fi +fi + +# Kill running instances before installing new files +echo "Stopping any running Viet+ processes..." +pkill -x vietc-tray 2>/dev/null || true +pkill -x vietc-daemon 2>/dev/null || true +pkill -x vietc-uinputd 2>/dev/null || true +pkill -x vietc 2>/dev/null || true + +# 2. Install Binaries +echo "Installing binaries to /usr/bin/..." +cp "$BIN_DAEMON" /usr/bin/vietc-daemon +cp "$BIN_CLI" /usr/bin/ +cp "$BIN_UINPUTD" /usr/bin/ +cp "$BIN_TRAY" /usr/bin/ +cp "$BIN_XRECORD" /usr/bin/ +chmod 755 /usr/bin/vietc-daemon /usr/bin/vietc-cli /usr/bin/vietc-uinputd /usr/bin/vietc-tray /usr/bin/vietc-xrecord + +# Remove old local path binaries to prevent shadows +rm -f /usr/local/bin/vietc-tray /usr/local/bin/vietc /usr/local/bin/vietc-daemon \ + /usr/local/bin/vietc-cli /usr/local/bin/vietc-uinputd /usr/local/bin/vietc-xrecord 2>/dev/null || true + +# 3. Install Icons +echo "Installing icons..." +mkdir -p /usr/share/icons/hicolor/256x256/apps +cp "$DIR_ICONS/vietc.svg" /usr/share/icons/hicolor/256x256/apps/ +cp "$DIR_ICONS/vietc-vn.svg" /usr/share/icons/hicolor/256x256/apps/ +cp "$DIR_ICONS/vietc-en.svg" /usr/share/icons/hicolor/256x256/apps/ +if command -v gtk-update-icon-cache >/dev/null 2>&1; then + gtk-update-icon-cache -f /usr/share/icons/hicolor/ >/dev/null 2>&1 || true +fi + +# 4. Install Desktop File +echo "Installing desktop launcher..." +mkdir -p /usr/share/applications +cp "$FILE_DESKTOP" /usr/share/applications/ + +# 5. Install Systemd User Service +echo "Installing systemd user service..." +mkdir -p /usr/lib/systemd/user +cat > /usr/lib/systemd/user/vietc.service << 'SERVICE' +[Unit] +Description=Viet+ Vietnamese IME Tray +PartOf=graphical-session.target + +[Service] +Type=simple +ExecStart=/usr/bin/vietc-tray +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target +SERVICE + +# 6. Install XDG Autostart +echo "Setting up autostart..." +mkdir -p /etc/xdg/autostart +cat > /etc/xdg/autostart/vietc-tray.desktop << 'AUTOSTART' +[Desktop Entry] +Type=Application +Name=Viet+ Tray +Comment=Vietnamese Input Method Tray +Exec=vietc-tray +Icon=vietc +Terminal=false +Categories=Utility; +StartupNotify=false +NoDisplay=true +AUTOSTART + +# 7. Install default config +echo "Installing default configuration..." +mkdir -p /etc/vietc +cp "$FILE_CONFIG" /etc/vietc/config.toml +chmod 644 /etc/vietc/config.toml + +# 8. Configure permissions (uinput) +echo "Installing udev rules for uinput access..." +mkdir -p /etc/udev/rules.d +cp "$FILE_RULES" /etc/udev/rules.d/99-vietc.rules +chmod 644 /etc/udev/rules.d/99-vietc.rules + +echo "Reloading udev rules..." +if command -v udevadm >/dev/null 2>&1; then + udevadm control --reload-rules >/dev/null 2>&1 || true + udevadm trigger --subsystem-match=misc >/dev/null 2>&1 || true +fi + +# Add active users to input group +INSTALLING_USER="${SUDO_USER:-${USER:-}}" +if [ -n "$INSTALLING_USER" ] && [ "$INSTALLING_USER" != "root" ]; then + echo "Adding user '$INSTALLING_USER' to group 'input'..." + if ! groups "$INSTALLING_USER" 2>/dev/null | grep -qw input; then + if command -v usermod >/dev/null 2>&1; then + usermod -aG input "$INSTALLING_USER" || true + elif command -v adduser >/dev/null 2>&1; then + adduser "$INSTALLING_USER" input || true + fi + fi + + # Remove any old conflicting configurations in user home + local user_home + user_home="$(getent passwd "$INSTALLING_USER" 2>/dev/null | cut -d: -f6 || true)" + if [ -n "$user_home" ]; then + rm -f "$user_home/.config/vietc/config.toml" 2>/dev/null || true + rm -f "$user_home/.config/vietc/overrides.toml" 2>/dev/null || true + rm -f "$user_home/.config/vietc/.first-launch-done" 2>/dev/null || true + fi +fi + +if command -v systemctl >/dev/null 2>&1; then + systemctl --global daemon-reload >/dev/null 2>&1 || true +fi + +echo -e "\n${GREEN}=== Installation Completed Successfully! ===${NC}" +echo -e "Please ${YELLOW}LOG OUT and LOG BACK IN${NC} to activate group permissions." +echo -e "Once logged back in, you can start Viet+ from your application launcher menu." diff --git a/packaging/99-vietc.rules b/packaging/99-vietc.rules new file mode 100644 index 0000000..0df0982 --- /dev/null +++ b/packaging/99-vietc.rules @@ -0,0 +1,3 @@ +# Udev rule for Viet+ input method +# Allows non-root users in the 'input' group to write to /dev/uinput +KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput" diff --git a/packaging/build-tarball.sh b/packaging/build-tarball.sh new file mode 100755 index 0000000..df02423 --- /dev/null +++ b/packaging/build-tarball.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT +# Viet+ — Generic Linux Tarball Packager +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +VERSION=$(grep '^version' "$PROJECT_ROOT/engine/Cargo.toml" | head -1 | sed 's/.*"\(.*\)"/\1/') + +PACKAGE_NAME="vietc_${VERSION}_linux_amd64" +DIST_DIR="$PROJECT_ROOT/target/dist" +STAGING="$DIST_DIR/$PACKAGE_NAME" + +echo "=== Building Viet+ release tarball v${VERSION} ===" + +# 1. Compile all components +echo "[1/4] Compiling components in release mode..." +cargo build --release --manifest-path "$PROJECT_ROOT/Cargo.toml" +(cd "$PROJECT_ROOT/ui" && cargo build --release) +gcc -O2 -o "$PROJECT_ROOT/target/release/vietc-xrecord" "$PROJECT_ROOT/packaging/deb/vietc-xrecord.c" -lX11 -lXtst + +# 2. Recreate staging directory +echo "[2/4] Assembling package structure..." +rm -rf "$DIST_DIR" +mkdir -p "$STAGING/bin" +mkdir -p "$STAGING/udev" +mkdir -p "$STAGING/desktop" +mkdir -p "$STAGING/icons" +mkdir -p "$STAGING/config" + +# 3. Copy binaries & rename vietc -> vietc-daemon +cp "$PROJECT_ROOT/target/release/vietc" "$STAGING/bin/vietc-daemon" +cp "$PROJECT_ROOT/target/release/vietc-cli" "$STAGING/bin/" +cp "$PROJECT_ROOT/target/release/vietc-uinputd" "$STAGING/bin/" +cp "$PROJECT_ROOT/ui/target/release/vietc-tray" "$STAGING/bin/" +cp "$PROJECT_ROOT/target/release/vietc-xrecord" "$STAGING/bin/" + +# 4. Copy assets & support files +cp "$PROJECT_ROOT/packaging/99-vietc.rules" "$STAGING/udev/" +cp "$PROJECT_ROOT/packaging/deb/vietc.desktop" "$STAGING/desktop/" +cp "$PROJECT_ROOT/vietc.toml" "$STAGING/config/config.toml" +cp "$PROJECT_ROOT/packaging/icons/vietc.svg" "$STAGING/icons/" +cp "$PROJECT_ROOT/packaging/icons/vietc-vn.svg" "$STAGING/icons/" +cp "$PROJECT_ROOT/packaging/icons/vietc-en.svg" "$STAGING/icons/" + +cp "$PROJECT_ROOT/install.sh" "$STAGING/" +chmod +x "$STAGING/install.sh" + +cp "$PROJECT_ROOT/README.md" "$STAGING/" +cp "$PROJECT_ROOT/LICENSE" "$STAGING/" + +# 5. Compress +echo "[3/4] Creating tarball archive..." +(cd "$DIST_DIR" && tar -czf "${PACKAGE_NAME}.tar.gz" "$PACKAGE_NAME") + +# 6. Cleanup temp staging +rm -rf "$STAGING" + +echo -e "\n=== Package successfully built: ===" +echo "target/dist/${PACKAGE_NAME}.tar.gz" diff --git a/packaging/deb/build-deb.sh b/packaging/deb/build-deb.sh index 75480bb..96dc605 100755 --- a/packaging/deb/build-deb.sh +++ b/packaging/deb/build-deb.sh @@ -27,6 +27,8 @@ mkdir -p "$STAGING/usr/share/icons/hicolor/256x256/apps" mkdir -p "$STAGING/usr/share/doc/vietc" mkdir -p "$STAGING/usr/share/metainfo" mkdir -p "$STAGING/etc/xdg/autostart" +mkdir -p "$STAGING/lib/udev/rules.d" + # Copy binaries echo "[3/5] Installing binaries..." @@ -46,6 +48,10 @@ cp "$PROJECT_ROOT/packaging/icons/vietc-en.svg" "$STAGING/usr/share/icons/hicolo # Desktop file cp "$SCRIPT_DIR/vietc.desktop" "$STAGING/usr/share/applications/" +# Udev rules +cp "$PROJECT_ROOT/packaging/99-vietc.rules" "$STAGING/lib/udev/rules.d/" + + # XDG autostart — launches tray on every login for all users cat > "$STAGING/etc/xdg/autostart/vietc-tray.desktop" << 'AUTOSTART' [Desktop Entry] @@ -122,7 +128,7 @@ Section: utils Priority: optional Architecture: amd64 Depends: libc6 (>= 2.31), libevdev2 (>= 1.9.0) -Recommends: libwayland-client0 (>= 1.20), libx11-6, libxtst6, libdbus-1-3, xclip +Recommends: libwayland-client0 (>= 1.20), libx11-6, libxtst6, libdbus-1-3, xclip, wl-clipboard Maintainer: Khoa Vo Description: Viet+ — Vietnamese Input Method for Linux Zero-configuration Vietnamese input method engine supporting @@ -206,6 +212,13 @@ case "$1" in if command -v gtk-update-icon-cache >/dev/null 2>&1; then gtk-update-icon-cache -f /usr/share/icons/hicolor/ >/dev/null 2>&1 || true fi + + # Reload udev rules to apply the new uinput rule + if command -v udevadm >/dev/null 2>&1; then + udevadm control --reload-rules >/dev/null 2>&1 || true + udevadm trigger --subsystem-match=misc >/dev/null 2>&1 || true + fi + ;; esac POSTINST