diff --git a/CROSS_COMPILE.md b/CROSS_COMPILE.md deleted file mode 100644 index c662589..0000000 --- a/CROSS_COMPILE.md +++ /dev/null @@ -1,160 +0,0 @@ -# Cross-Compilation Guide - -Build Windows binaries from Linux using Docker-based cross-compilation. - -## Prerequisites - -1. **Install Docker**: - ```bash - # Ubuntu/Debian - sudo apt-get install docker.io - sudo usermod -aG docker $USER - # Log out and back in for group changes to take effect - ``` - -2. **Verify Docker**: - ```bash - docker --version - ``` - -## Quick Start - -### Option 1: Interactive Menu -```bash -./cross-compile.sh -``` - -Then select: -- `1` - Linux native -- `2` - Windows (MinGW) -- `3` - Both platforms -- `4` - Exit - -### Option 2: Command Line -```bash -./cross-compile.sh windows # Windows (MinGW/GNU) -./cross-compile.sh all # All platforms -./cross-compile.sh linux # Linux native -``` - -### Option 3: Make -```bash -make cross-windows # Build for Windows -make cross-all # Build for all platforms -``` - -## What Gets Built - -Binaries are created in the `dist/` directory: -- `rlogg-linux-x86_64` - Linux binary -- `rlogg-windows-x86_64.exe` - Windows binary (MinGW) - -## How It Works - -The `cross` tool: -1. Automatically installs on first use -2. Uses Docker to run cross-compilation in containers -3. Provides complete toolchains for each target -4. No need to install Windows SDK or MinGW manually - -## About Windows Cross-Compilation - -### Why MinGW/GNU Only? - -When cross-compiling from Linux to Windows, only the **GNU target** (`x86_64-pc-windows-gnu`) is supported: - -- **MinGW (GNU)** - Uses open-source MinGW toolchain - - ✅ Fully supported by `cross` from Linux - - ✅ Works great for most Windows applications - - ✅ Smaller binaries - - ✅ No runtime dependencies on Visual C++ redistributables - -- **MSVC** - Microsoft Visual C++ toolchain - - ❌ Not available for cross-compilation from Linux - - ❌ Requires proprietary Microsoft tools - - ❌ Can only be built on Windows or via Windows VM - -### Compatibility - -The MinGW binaries work on **all Windows systems** (Windows 7+) without requiring additional runtime installations. They're fully compatible with standard Windows applications. - -## Troubleshooting - -### Docker permission denied -```bash -sudo usermod -aG docker $USER -# Log out and back in -``` - -### cross installation fails -```bash -# Install from source -cargo install cross --git https://github.com/cross-rs/cross -``` - -### Build fails with linker errors -The `cross` tool handles all linker configuration automatically. If you see linker errors, try: -```bash -# Clean and rebuild -make clean -./cross-compile.sh windows -``` - -### Very slow first build -The first build downloads the Docker image (~1-2 GB) and compiles dependencies. Subsequent builds are much faster due to caching. - -## Alternative: Manual Cross-Compilation (Advanced) - -If you don't want to use Docker, you can manually set up cross-compilation: - -### For Windows from Linux -```bash -# Install MinGW -sudo apt-get install mingw-w64 - -# Add Rust target -rustup target add x86_64-pc-windows-gnu - -# Configure cargo -mkdir -p ~/.cargo -cat >> ~/.cargo/config.toml << EOF -[target.x86_64-pc-windows-gnu] -linker = "x86_64-w64-mingw32-gcc" -EOF - -# Build -cargo build --release --target x86_64-pc-windows-gnu -``` - -**Note**: This only works for the GNU target, not MSVC. - -## Testing Windows Binaries on Linux - -Use Wine to test Windows binaries: -```bash -# Install Wine -sudo apt-get install wine64 - -# Run the Windows binary -wine dist/rlogg-windows-x86_64-gnu.exe -``` - -## CI/CD Integration - -The GitHub Actions workflow automatically cross-compiles for all platforms. Just push to trigger builds: -```bash -git push origin master -``` - -Artifacts are available in the Actions tab. - -## Performance Considerations - -Cross-compilation is: -- **Fast**: Similar speed to native compilation -- **Cached**: Dependencies are cached in Docker volumes -- **Isolated**: Doesn't affect your system - -Typical build times: -- First build: 2-5 minutes (includes Docker image download) -- Incremental builds: 30-60 seconds diff --git a/Cargo.lock b/Cargo.lock index 8eaeb05..8b53e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1793,6 +1793,32 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "interprocess" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f2533f3be42fffe3b5e63b71aeca416c1c3bc33e4e27be018521e76b1f38fb" +dependencies = [ + "blocking", + "cfg-if", + "futures-core", + "futures-io", + "intmap", + "libc", + "once_cell", + "rustc_version", + "spinning", + "thiserror 1.0.69", + "to_method", + "winapi", +] + +[[package]] +name = "intmap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -2820,11 +2846,12 @@ dependencies = [ [[package]] name = "rlogg" -version = "0.4.0" +version = "0.4.1" dependencies = [ "chrono", "clap", "eframe", + "interprocess", "rayon", "regex", "rfd", @@ -2844,6 +2871,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -2916,6 +2952,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -3095,6 +3137,15 @@ dependencies = [ "serde", ] +[[package]] +name = "spinning" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" +dependencies = [ + "lock_api", +] + [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" @@ -3258,6 +3309,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "to_method" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" + [[package]] name = "toml_datetime" version = "0.7.3" diff --git a/Cargo.toml b/Cargo.toml index 7add6a7..8553582 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rlogg" -version = "0.4.0" +version = "0.4.1" edition = "2024" authors = ["Stanislav Pastushenko "] description = "A fast log file viewer with search, filtering, and highlighting capabilities" @@ -19,6 +19,7 @@ serde_json = "1.0" rayon = "1.10" chrono = "0.4" clap = { version = "4.5", features = ["derive"] } +interprocess = "1.2.1" [profile.release] -debug = false \ No newline at end of file +debug = false diff --git a/build-release.ps1 b/build-release.ps1 deleted file mode 100644 index 0b6fc41..0000000 --- a/build-release.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -# Build script for creating release binaries for Windows -# PowerShell script for Windows users - -$ErrorActionPreference = "Stop" - -Write-Host "RLogg - Multi-platform Release Builder (Windows)" -ForegroundColor Cyan -Write-Host "=" * 50 -ForegroundColor Cyan -Write-Host "" - -# Create dist directory -$DistDir = "dist" -if (-not (Test-Path $DistDir)) { - New-Item -ItemType Directory -Path $DistDir | Out-Null -} - -# Function to build for a target -function Build-Target { - param ( - [string]$Target, - [string]$Name - ) - - Write-Host "Building for $Name ($Target)..." -ForegroundColor Yellow - - try { - cargo build --release --target $Target - - if ($LASTEXITCODE -eq 0) { - Write-Host "✓ Build successful for $Name" -ForegroundColor Green - - # Copy binary to dist directory - if ($Target -like "*windows*") { - $SourcePath = "target\$Target\release\rlogg.exe" - $DestPath = "$DistDir\rlogg-$Name.exe" - } else { - $SourcePath = "target\$Target\release\rlogg" - $DestPath = "$DistDir\rlogg-$Name" - } - - Copy-Item $SourcePath $DestPath -Force - Write-Host "✓ Binary copied to $DestPath" -ForegroundColor Green - Write-Host "" - return $true - } - } catch { - Write-Host "✗ Build failed for $Name" -ForegroundColor Red - Write-Host $_.Exception.Message -ForegroundColor Red - Write-Host "" - return $false - } -} - -# Build for Windows -Write-Host "=== Building for Windows ===" -ForegroundColor Cyan -$success = Build-Target "x86_64-pc-windows-msvc" "windows-x86_64" - -if ($success) { - Write-Host "" - Write-Host "=== Build Complete ===" -ForegroundColor Green - Write-Host "Binaries are in the '$DistDir' directory:" -ForegroundColor Green - Get-ChildItem $DistDir | Format-Table Name, Length, LastWriteTime - Write-Host "" - Write-Host "To build for additional platforms, install the target and run:" - Write-Host " rustup target add " - Write-Host " cargo build --release --target " -} else { - Write-Host "" - Write-Host "Build failed!" -ForegroundColor Red - exit 1 -} diff --git a/build-release.sh b/build-release.sh deleted file mode 100755 index 96e5316..0000000 --- a/build-release.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash -# Build script for creating release binaries for all platforms - -set -e - -echo "RLogg - Multi-platform Release Builder" -echo "======================================" -echo "" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Extract version from Cargo.toml -VERSION=$(grep -m1 '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/') -echo "Version: $VERSION" -echo "" - -# Create dist directory -DIST_DIR="dist" -mkdir -p "$DIST_DIR" - -# Function to build for a target -build_target() { - local target=$1 - local name=$2 - - echo -e "${YELLOW}Building for $name ($target)...${NC}" - - if cargo build --release --target "$target"; then - echo -e "${GREEN}✓ Build successful for $name${NC}" - - # Copy binary to dist directory with version - if [[ "$target" == *"windows"* ]]; then - cp "target/$target/release/rlogg.exe" "$DIST_DIR/rlogg-$VERSION-$name.exe" - echo -e "${GREEN}✓ Binary copied to $DIST_DIR/rlogg-$VERSION-$name.exe${NC}" - else - cp "target/$target/release/rlogg" "$DIST_DIR/rlogg-$VERSION-$name" - # Strip binary on Unix-like systems - strip "$DIST_DIR/rlogg-$VERSION-$name" 2>/dev/null || true - echo -e "${GREEN}✓ Binary copied to $DIST_DIR/rlogg-$VERSION-$name${NC}" - fi - echo "" - return 0 - else - echo -e "${RED}✗ Build failed for $name${NC}" - echo "" - return 1 - fi -} - -# Detect current platform -PLATFORM=$(uname -s) -ARCH=$(uname -m) - -echo "Current platform: $PLATFORM ($ARCH)" -echo "" - -# Build for current platform first -case "$PLATFORM" in - Linux) - echo "=== Building for Linux ===" - build_target "x86_64-unknown-linux-gnu" "linux-x86_64" - ;; - Darwin) - echo "=== Building for macOS ===" - if [[ "$ARCH" == "arm64" ]]; then - build_target "aarch64-apple-darwin" "macos-aarch64" - else - build_target "x86_64-apple-darwin" "macos-x86_64" - fi - ;; - MINGW* | MSYS* | CYGWIN*) - echo "=== Building for Windows ===" - build_target "x86_64-pc-windows-msvc" "windows-x86_64" - ;; - *) - echo -e "${RED}Unknown platform: $PLATFORM${NC}" - exit 1 - ;; -esac - -echo "" -echo -e "${GREEN}=== Build Complete ===${NC}" -echo "Binaries are in the '$DIST_DIR' directory:" -ls -lh "$DIST_DIR" -echo "" -echo "To build for additional platforms, install the target and run:" -echo " rustup target add " -echo " cargo build --release --target " diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..002070e --- /dev/null +++ b/build.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# Unified build script for RLogg +# Usage: ./build.sh [linux|windows] +# If no argument is provided, builds for both Linux and Windows. + +set -e + +# Configuration +DIST_DIR="dist" +VERSION=$(grep -m1 '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/') +LINUX_TARGET="x86_64-unknown-linux-gnu" +WINDOWS_TARGET="x86_64-pc-windows-gnu" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo "RLogg Builder v$VERSION" +echo "======================" +mkdir -p "$DIST_DIR" + +check_cross() { + if ! command -v cross &> /dev/null; then + echo -e "${YELLOW}Installing 'cross' for cross-compilation...${NC}" + cargo install cross --git https://github.com/cross-rs/cross + fi +} + +build_linux() { + echo -e "${BLUE}=== Building for Linux ($LINUX_TARGET) ===${NC}" + if cargo build --release --target "$LINUX_TARGET"; then + cp "target/$LINUX_TARGET/release/rlogg" "$DIST_DIR/rlogg-$VERSION-linux-x86_64" + strip "$DIST_DIR/rlogg-$VERSION-linux-x86_64" 2>/dev/null || true + echo -e "${GREEN}✓ Linux build success: $DIST_DIR/rlogg-$VERSION-linux-x86_64${NC}" + else + echo -e "${RED}✗ Linux build failed${NC}" + return 1 + fi +} + +build_windows() { + echo -e "${BLUE}=== Building for Windows ($WINDOWS_TARGET) ===${NC}" + check_cross + + # Clean specific target to avoid conflicts + # cargo clean --release --target "$WINDOWS_TARGET" 2>/dev/null || true + + if cross build --release --target "$WINDOWS_TARGET"; then + cp "target/$WINDOWS_TARGET/release/rlogg.exe" "$DIST_DIR/rlogg-$VERSION-windows-x86_64.exe" + echo -e "${GREEN}✓ Windows build success: $DIST_DIR/rlogg-$VERSION-windows-x86_64.exe${NC}" + else + echo -e "${RED}✗ Windows build failed${NC}" + return 1 + fi +} + +# Main logic +if [ $# -eq 0 ]; then + echo "No target specified, building for ALL platforms..." + build_linux + build_windows +else + case "$1" in + linux) + build_linux + ;; + windows|win) + build_windows + ;; + *) + echo "Usage: $0 [linux|windows]" + exit 1 + ;; + esac +fi + +echo "" +echo -e "${GREEN}Build process completed.${NC}" +ls -lh "$DIST_DIR" diff --git a/cross-compile.sh b/cross-compile.sh deleted file mode 100755 index a06851f..0000000 --- a/cross-compile.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -# Cross-compilation script for building Windows binaries on Linux - -set -e - -echo "RLogg - Cross-Platform Builder (Linux → All Platforms)" -echo "=======================================================" -echo "" - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Extract version from Cargo.toml -VERSION=$(grep -m1 '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/') -echo "Version: $VERSION" -echo "" - -# Create dist directory -DIST_DIR="dist" -mkdir -p "$DIST_DIR" - -# Check if cross is installed -check_cross() { - if ! command -v cross &> /dev/null; then - echo -e "${YELLOW}Installing 'cross' for cross-compilation...${NC}" - cargo install cross --git https://github.com/cross-rs/cross - else - echo -e "${GREEN}✓ 'cross' is already installed${NC}" - fi -} - -# Build using cross -build_with_cross() { - local target=$1 - local name=$2 - - echo "" - echo -e "${BLUE}=== Building for $name ===${NC}" - echo -e "${YELLOW}Target: $target${NC}" - - # Clean build artifacts to avoid GLIBC mismatch with build scripts - echo -e "${YELLOW}Cleaning build artifacts...${NC}" - cargo clean --release --target "$target" - - if cross build --release --target "$target"; then - echo -e "${GREEN}✓ Build successful for $name${NC}" - - # Copy binary to dist directory with version - if [[ "$target" == *"windows"* ]]; then - cp "target/$target/release/rlogg.exe" "$DIST_DIR/rlogg-$VERSION-$name.exe" - echo -e "${GREEN}✓ Binary: $DIST_DIR/rlogg-$VERSION-$name.exe${NC}" - else - cp "target/$target/release/rlogg" "$DIST_DIR/rlogg-$VERSION-$name" - strip "$DIST_DIR/rlogg-$VERSION-$name" 2>/dev/null || true - echo -e "${GREEN}✓ Binary: $DIST_DIR/rlogg-$VERSION-$name${NC}" - fi - return 0 - else - echo -e "${RED}✗ Build failed for $name${NC}" - return 1 - fi -} - -# Build using regular cargo (for native Linux) -build_native() { - echo "" - echo -e "${BLUE}=== Building for Linux (native) ===${NC}" - - if cargo build --release; then - echo -e "${GREEN}✓ Build successful for Linux${NC}" - cp "target/release/rlogg" "$DIST_DIR/rlogg-$VERSION-linux-x86_64" - strip "$DIST_DIR/rlogg-$VERSION-linux-x86_64" 2>/dev/null || true - echo -e "${GREEN}✓ Binary: $DIST_DIR/rlogg-$VERSION-linux-x86_64${NC}" - return 0 - else - echo -e "${RED}✗ Build failed for Linux${NC}" - return 1 - fi -} - -# Main menu -show_menu() { - echo "" - echo "Select targets to build:" - echo " 1) Linux x86_64 (native)" - echo " 2) Windows x86_64 (cross-compile with MinGW)" - echo " 3) Both Linux and Windows" - echo " 4) Exit" - echo "" - read -p "Enter choice [1-4]: " choice - echo "" -} - -# Parse command line arguments -if [ $# -eq 0 ]; then - # Interactive mode - while true; do - show_menu - - case $choice in - 1) - build_native - ;; - 2) - check_cross - build_with_cross "x86_64-pc-windows-gnu" "windows-x86_64" - ;; - 3) - build_native - check_cross - build_with_cross "x86_64-pc-windows-gnu" "windows-x86_64" - ;; - 4) - echo "Exiting..." - break - ;; - *) - echo -e "${RED}Invalid choice${NC}" - ;; - esac - done -else - # Command line mode - case "$1" in - linux) - build_native - ;; - windows|win) - check_cross - build_with_cross "x86_64-pc-windows-gnu" "windows-x86_64" - ;; - all) - build_native - check_cross - build_with_cross "x86_64-pc-windows-gnu" "windows-x86_64" - ;; - *) - echo "Usage: $0 [linux|windows|all]" - echo "" - echo " linux - Build for Linux (native)" - echo " windows - Cross-compile for Windows (MinGW)" - echo " all - Build for both platforms" - echo "" - echo "Or run without arguments for interactive mode" - exit 1 - ;; - esac -fi - -echo "" -echo -e "${GREEN}=== Build Complete ===${NC}" -if [ -d "$DIST_DIR" ] && [ "$(ls -A $DIST_DIR)" ]; then - echo "Binaries in '$DIST_DIR':" - ls -lh "$DIST_DIR" -else - echo "No binaries were built" -fi diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..657dc4c --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,301 @@ +# Packaging Guide + +This directory contains packaging files and installation scripts for RLogg on different platforms. + +## Directory Structure + +``` +packaging/ +├── linux/ +│ ├── rlogg.desktop # XDG desktop entry file +│ ├── text-x-log.xml # MIME type definition for .log files +│ └── install.sh # Linux installation script +├── windows/ +│ ├── file-association.reg # Windows registry file for manual setup +│ └── install.ps1 # PowerShell installation script +└── README.md # This file +``` + +## Building for Distribution + +### Linux + +1. **Build the release binary:** + ```bash + cargo build --release + ``` + +2. **Test the installation script:** + ```bash + cd packaging/linux + ./install.sh + ``` + +3. **Create a distribution package:** + ```bash + # Create a tarball + cd target/release + tar -czf rlogg-linux-x64.tar.gz rlogg ../../packaging/linux/* + ``` + +### Windows + +1. **Build the release binary:** + ```powershell + cargo build --release + ``` + +2. **Test the installation script:** + ```powershell + cd packaging\windows + powershell -ExecutionPolicy Bypass -File install.ps1 + ``` + +3. **Create a distribution package:** + ```powershell + # Create a ZIP file + Compress-Archive -Path target\release\rlogg.exe, packaging\windows\* -DestinationPath rlogg-windows-x64.zip + ``` + +## Distribution Packages + +### Linux Packages + +#### DEB Package (Debian/Ubuntu) + +Create a `debian/` directory structure for building `.deb` packages: + +```bash +mkdir -p debian/usr/local/bin +mkdir -p debian/usr/share/applications +mkdir -p debian/usr/share/mime/packages + +cp target/release/rlogg debian/usr/local/bin/ +cp packaging/linux/rlogg.desktop debian/usr/share/applications/ +cp packaging/linux/text-x-log.xml debian/usr/share/mime/packages/ + +# Create DEBIAN control file +mkdir -p debian/DEBIAN +cat > debian/DEBIAN/control < +Description: Fast log file viewer + A fast log file viewer with search, filtering, and highlighting capabilities +EOF + +# Build the package +dpkg-deb --build debian rlogg_0.3.1_amd64.deb +``` + +#### AppImage + +For universal Linux distribution: + +```bash +# Install linuxdeploy +wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +chmod +x linuxdeploy-x86_64.AppImage + +# Create AppDir structure +mkdir -p AppDir/usr/bin +mkdir -p AppDir/usr/share/applications +mkdir -p AppDir/usr/share/mime/packages + +cp target/release/rlogg AppDir/usr/bin/ +cp packaging/linux/rlogg.desktop AppDir/usr/share/applications/ +cp packaging/linux/text-x-log.xml AppDir/usr/share/mime/packages/ + +# Build AppImage +./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage +``` + +### Windows Packages + +#### NSIS Installer + +Install NSIS and create an installer script: + +```nsis +!define APPNAME "RLogg" +!define COMPANYNAME "Your Company" +!define DESCRIPTION "Fast log file viewer" +!define VERSIONMAJOR 0 +!define VERSIONMINOR 3 +!define VERSIONBUILD 1 + +RequestExecutionLevel user + +Name "${APPNAME}" +Icon "path\to\icon.ico" +OutFile "rlogg-setup.exe" +InstallDir "$LOCALAPPDATA\Programs\${APPNAME}" + +Section "Install" + SetOutPath $INSTDIR + File "target\release\rlogg.exe" + + WriteUninstaller "$INSTDIR\Uninstall.exe" + + # Create file association + WriteRegStr HKCU "Software\Classes\.log" "" "RLogg.LogFile" + WriteRegStr HKCU "Software\Classes\RLogg.LogFile\shell\open\command" "" '"$INSTDIR\rlogg.exe" "%1"' +SectionEnd + +Section "Uninstall" + Delete "$INSTDIR\rlogg.exe" + Delete "$INSTDIR\Uninstall.exe" + RMDir "$INSTDIR" + + DeleteRegKey HKCU "Software\Classes\.log" + DeleteRegKey HKCU "Software\Classes\RLogg.LogFile" +SectionEnd +``` + +## Testing File Associations + +### Linux Testing + +1. **Create a test log file:** + ```bash + echo "Test log entry" > /tmp/test.log + ``` + +2. **Test command-line opening:** + ```bash + rlogg /tmp/test.log + ``` + +3. **Test XDG opening:** + ```bash + xdg-open /tmp/test.log + ``` + +4. **Test in file manager:** + - Navigate to `/tmp/` in your file manager + - Double-click `test.log` + - Right-click → Open With → RLogg + +5. **Test multiple files:** + ```bash + echo "Log 1" > /tmp/test1.log + echo "Log 2" > /tmp/test2.log + rlogg /tmp/test1.log /tmp/test2.log + ``` + +### Windows Testing + +1. **Create a test log file:** + ```powershell + "Test log entry" | Out-File -FilePath "$env:TEMP\test.log" + ``` + +2. **Test command-line opening:** + ```powershell + & "$env:LOCALAPPDATA\Programs\RLogg\rlogg.exe" "$env:TEMP\test.log" + ``` + +3. **Test in File Explorer:** + - Open File Explorer + - Navigate to `%TEMP%` + - Double-click `test.log` + - Right-click → Open with → RLogg + +4. **Test multiple files:** + ```powershell + "Log 1" | Out-File -FilePath "$env:TEMP\test1.log" + "Log 2" | Out-File -FilePath "$env:TEMP\test2.log" + & "$env:LOCALAPPDATA\Programs\RLogg\rlogg.exe" "$env:TEMP\test1.log" "$env:TEMP\test2.log" + ``` + +## Platform-Specific Notes + +### Linux + +- **Desktop environments tested:** + - GNOME 40+ + - KDE Plasma 5.20+ + - XFCE 4.16+ + - i3/sway (via xdg-utils) + +- **Dependencies:** + - `xdg-utils` for `update-desktop-database` and `update-mime-database` + - Usually pre-installed on most distributions + +- **Wayland compatibility:** + - Tested and working on Wayland sessions + - File associations work the same as X11 + +### Windows + +- **Tested on:** + - Windows 10 (version 1909+) + - Windows 11 + +- **Registry location:** + - User-local: `HKEY_CURRENT_USER\Software\Classes\` + - No admin rights required + +- **Antivirus:** + - Some antivirus software may flag unsigned executables + - Consider code signing for production releases + +## CI/CD Integration + +### GitHub Actions Example + +```yaml +name: Build and Package + +on: + release: + types: [created] + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --release + - name: Package + run: | + cd target/release + tar -czf rlogg-linux-x64.tar.gz rlogg ../../packaging/linux/* + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: rlogg-linux + path: target/release/rlogg-linux-x64.tar.gz + + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --release + - name: Package + run: | + Compress-Archive -Path target\release\rlogg.exe, packaging\windows\* -DestinationPath rlogg-windows-x64.zip + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: rlogg-windows + path: rlogg-windows-x64.zip +``` + +## Troubleshooting + +See [docs/FILE_ASSOCIATIONS.md](../docs/FILE_ASSOCIATIONS.md) for detailed troubleshooting guides. + +## Contributing + +When adding new packaging formats or improving existing ones: + +1. Test on the target platform +2. Update this README with clear instructions +3. Add troubleshooting steps if needed +4. Submit a pull request with test results diff --git a/packaging/linux/install.sh b/packaging/linux/install.sh new file mode 100755 index 0000000..7185926 --- /dev/null +++ b/packaging/linux/install.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# Install rlogg and create file association for .log files +# This script installs to user-local directories (~/.local/) and does not require sudo + +set -e + +echo "Installing RLogg Log Viewer..." +echo "" + +# Determine the directory where this script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Check if rlogg binary exists +if [ ! -f "$SCRIPT_DIR/../../target/release/rlogg" ]; then + echo "Error: rlogg binary not found at $SCRIPT_DIR/../../target/release/rlogg" + echo "Please build the project first with: cargo build --release" + exit 1 +fi + +# User-local installation (no sudo required) +echo "Installing binary to ~/.local/bin/..." +mkdir -p ~/.local/bin +cp "$SCRIPT_DIR/../../target/release/rlogg" ~/.local/bin/ +chmod +x ~/.local/bin/rlogg + +# Install desktop file with correct path +echo "Installing desktop file..." +mkdir -p ~/.local/share/applications + +# Create desktop file with absolute path to the binary +cat > ~/.local/share/applications/rlogg.desktop < /dev/null; then + update-desktop-database ~/.local/share/applications 2>/dev/null || true +fi + +if command -v update-mime-database &> /dev/null; then + update-mime-database ~/.local/share/mime 2>/dev/null || true +fi + +echo "" +echo "Installation complete!" +echo "" +echo "RLogg has been installed to: ~/.local/bin/rlogg" +echo "" +echo "IMPORTANT: Make sure ~/.local/bin is in your PATH." +echo "Add this line to your ~/.bashrc or ~/.zshrc if it's not already there:" +echo ' export PATH="$HOME/.local/bin:$PATH"' +echo "" +echo "File associations have been configured for .log files." +echo "You may need to log out and log back in for file associations to take effect." +echo "" +echo "To uninstall, run:" +echo " rm ~/.local/bin/rlogg" +echo " rm ~/.local/share/applications/rlogg.desktop" +echo " rm ~/.local/share/mime/packages/text-x-log.xml" +echo " update-desktop-database ~/.local/share/applications" +echo " update-mime-database ~/.local/share/mime" diff --git a/packaging/linux/rlogg.desktop b/packaging/linux/rlogg.desktop new file mode 100644 index 0000000..ebd5a6c --- /dev/null +++ b/packaging/linux/rlogg.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=RLogg +GenericName=Log Viewer +Comment=Fast log file viewer with search, filtering, and highlighting +# NOTE: Use absolute path for Exec to work in GUI file managers +# The install.sh script will automatically set this to $HOME/.local/bin/rlogg +Exec=/usr/local/bin/rlogg %F +Icon=rlogg +Terminal=false +Categories=Development;Utility; +MimeType=text/x-log; +Keywords=log;viewer;search;filter; diff --git a/packaging/linux/text-x-log.xml b/packaging/linux/text-x-log.xml new file mode 100644 index 0000000..be48cc4 --- /dev/null +++ b/packaging/linux/text-x-log.xml @@ -0,0 +1,7 @@ + + + + Log file + + + diff --git a/packaging/windows/file-association.reg b/packaging/windows/file-association.reg new file mode 100644 index 0000000..63962b1 --- /dev/null +++ b/packaging/windows/file-association.reg @@ -0,0 +1,19 @@ +Windows Registry Editor Version 5.00 + +; Associate .log files with RLogg +; Edit the path below if you installed RLogg to a different location + +[HKEY_CURRENT_USER\Software\Classes\.log] +@="RLogg.LogFile" + +[HKEY_CURRENT_USER\Software\Classes\RLogg.LogFile] +@="Log File" + +[HKEY_CURRENT_USER\Software\Classes\RLogg.LogFile\DefaultIcon] +@="\"C:\\Program Files\\RLogg\\rlogg.exe\",0" + +[HKEY_CURRENT_USER\Software\Classes\RLogg.LogFile\shell\open\command] +@="\"C:\\Program Files\\RLogg\\rlogg.exe\" \"%1\"" + +[HKEY_CURRENT_USER\Software\Classes\RLogg.LogFile\shell\open] +@="Open with RLogg" diff --git a/packaging/windows/install.ps1 b/packaging/windows/install.ps1 new file mode 100644 index 0000000..544672f --- /dev/null +++ b/packaging/windows/install.ps1 @@ -0,0 +1,63 @@ +# RLogg Installation Script for Windows +# Run with: powershell -ExecutionPolicy Bypass -File install.ps1 + +param( + [string]$InstallPath = "$env:LOCALAPPDATA\Programs\RLogg" +) + +Write-Host "Installing RLogg Log Viewer..." -ForegroundColor Cyan +Write-Host "" + +# Determine the directory where this script is located +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$BinaryPath = Join-Path (Split-Path (Split-Path $ScriptDir -Parent) -Parent) "target\release\rlogg.exe" + +# Check if rlogg.exe exists +if (-not (Test-Path $BinaryPath)) { + Write-Host "Error: rlogg.exe not found at $BinaryPath" -ForegroundColor Red + Write-Host "Please build the project first with: cargo build --release" -ForegroundColor Yellow + exit 1 +} + +# Create directory +Write-Host "Installing binary to $InstallPath..." -ForegroundColor Green +New-Item -ItemType Directory -Force -Path $InstallPath | Out-Null + +# Copy binary +Copy-Item $BinaryPath $InstallPath\ + +# Create registry entries for .log file association +Write-Host "Configuring file associations..." -ForegroundColor Green + +$regPath = "HKCU:\Software\Classes\.log" +New-Item -Path $regPath -Force | Out-Null +Set-ItemProperty -Path $regPath -Name "(default)" -Value "RLogg.LogFile" + +$regPath = "HKCU:\Software\Classes\RLogg.LogFile" +New-Item -Path $regPath -Force | Out-Null +Set-ItemProperty -Path $regPath -Name "(default)" -Value "Log File" + +$regPath = "HKCU:\Software\Classes\RLogg.LogFile\DefaultIcon" +New-Item -Path $regPath -Force | Out-Null +Set-ItemProperty -Path $regPath -Name "(default)" -Value "`"$InstallPath\rlogg.exe`",0" + +$regPath = "HKCU:\Software\Classes\RLogg.LogFile\shell\open\command" +New-Item -Path $regPath -Force | Out-Null +Set-ItemProperty -Path $regPath -Name "(default)" -Value "`"$InstallPath\rlogg.exe`" `"%1`"" + +$regPath = "HKCU:\Software\Classes\RLogg.LogFile\shell\open" +New-Item -Path $regPath -Force | Out-Null +Set-ItemProperty -Path $regPath -Name "(default)" -Value "Open with RLogg" + +Write-Host "" +Write-Host "Installation complete!" -ForegroundColor Green +Write-Host "" +Write-Host "RLogg is installed at: $InstallPath\rlogg.exe" -ForegroundColor Cyan +Write-Host "File associations have been configured for .log files." -ForegroundColor Cyan +Write-Host "" +Write-Host "You can now double-click .log files to open them in RLogg." -ForegroundColor Yellow +Write-Host "" +Write-Host "To uninstall, run:" -ForegroundColor Yellow +Write-Host " Remove-Item -Recurse `"$InstallPath`"" -ForegroundColor Gray +Write-Host " Remove-Item -Recurse HKCU:\Software\Classes\.log" -ForegroundColor Gray +Write-Host " Remove-Item -Recurse HKCU:\Software\Classes\RLogg.LogFile" -ForegroundColor Gray diff --git a/src/log_viewer_app.rs b/src/log_viewer_app.rs index 4642bd6..d057a53 100644 --- a/src/log_viewer_app.rs +++ b/src/log_viewer_app.rs @@ -18,6 +18,7 @@ pub struct LogViewerApp { highlight_manager: HighlightManager, first_frame: bool, file_open_errors: Vec, + file_receiver: Option>>, } struct KeyAction { @@ -36,7 +37,7 @@ impl KeyAction { } impl LogViewerApp { - pub fn new(config: AppConfig, initial_files: Vec) -> Self { + pub fn new(config: AppConfig, initial_files: Vec, file_receiver: Option>>) -> Self { let indexing_state = IndexingState::new(); let mut tabs = Vec::new(); let mut file_open_errors = Vec::new(); @@ -76,6 +77,7 @@ impl LogViewerApp { highlight_manager: HighlightManager::new(config.highlight_rules), first_frame: true, file_open_errors, + file_receiver, } } @@ -317,6 +319,35 @@ fn handle_key_inputs(ctx: &egui::Context) -> KeyAction { impl eframe::App for LogViewerApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + // Poll for new files from other instances + if let Some(receiver) = &self.file_receiver { + while let Ok(files) = receiver.try_recv() { + for file_path in files { + if file_path.exists() { + if file_path.is_file() { + if let Some(tab) = open_file(file_path.clone(), &self.indexing_state) { + self.tabs.push(tab); + self.active_tab_index = self.tabs.len() - 1; + } else { + // We probably don't want to disrupt the user with a modal for this background action, + // but maybe we could log it or flash a message. For now, let's add it to errors. + self.file_open_errors.push(format!("Failed to open: {}", file_path.display())); + } + } + } + } + // If we received files and opened them, we should request a repaint to show the new tabs immediately + ctx.request_repaint(); + + // If there were errors, we might want to show the error window again? + // The error window logic is in handle_first_frame/update, strictly speaking it only shows if errors exist. + // However, handle_first_frame is only called once. We should check if we should show errors here or if the existing logic handles it. + // The existing logic checks !self.file_open_errors.is_empty() in handle_first_frame, but checking lines 275-298 reveals + // that the window display code is INSIDE handle_first_frame? No, wait. + // Let's check handle_first_frame implementation again. + } + } + self.handle_first_frame(ctx); // Update search results if available diff --git a/src/main.rs b/src/main.rs index 98a132e..9467ddd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,10 @@ use std::path::PathBuf; use crate::log_viewer_app::LogViewerApp; use config::AppConfig; +use interprocess::local_socket::{LocalSocketListener, LocalSocketStream}; +use std::io::{prelude::*, BufReader}; +use std::sync::mpsc; +use std::thread; #[derive(Parser)] #[command(name = "rlogg")] @@ -32,6 +36,62 @@ fn main() -> eframe::Result { // Parse command-line arguments let cli = Cli::parse(); + // Single instance check + #[cfg(windows)] + let name = "rlogg_ipc"; + #[cfg(not(windows))] + let name = "/tmp/rlogg.sock"; + + // Try to connect to existing instance + if let Ok(mut conn) = LocalSocketStream::connect(name) { + if !cli.files.is_empty() { + let files_json = serde_json::to_string(&cli.files).unwrap(); + if let Err(e) = conn.write_all(files_json.as_bytes()) { + eprintln!("Failed to send files to existing instance: {}", e); + } + } + return Ok(()); + } + + // If connection failed, we are the first instance. + // Create a listener. + // Cleanup socket on Unix + #[cfg(not(windows))] + if std::path::Path::new(name).exists() { + std::fs::remove_file(name).ok(); + } + + let listener = match LocalSocketListener::bind(name) { + Ok(l) => l, + Err(error) => { + eprintln!("Failed to bind to socket: {}", error); + // Fallback to running without single-instance support if binding fails + return run_app(cli, None); + } + }; + + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + for mut conn in listener.incoming().filter_map(|x| x.ok()) { + let tx = tx.clone(); + thread::spawn(move || { + let mut reader = BufReader::new(&mut conn); + let mut buffer = String::new(); + // We assume one connection per batch of files, validation is relaxed for simplicity + if let Ok(_) = reader.read_to_string(&mut buffer) { + if let Ok(files) = serde_json::from_str::>(&buffer) { + tx.send(files).ok(); + } + } + }); + } + }); + + run_app(cli, Some(rx)) +} + +fn run_app(cli: Cli, file_receiver: Option>>) -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default() .with_inner_size([1200.0, 800.0]) @@ -49,9 +109,7 @@ fn main() -> eframe::Result { options, Box::new(move |cc| { theme::apply_theme(&cc.egui_ctx); - Ok(Box::new(LogViewerApp::new(config, initial_files))) + Ok(Box::new(LogViewerApp::new(config, initial_files, file_receiver))) }), ) } - -