Loading pkgs/by-name/ta/tabularis/disable-updater.patch 0 → 100644 +543 −0 Original line number Diff line number Diff line diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e74f8c5..5333b4a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -59,8 +59,5 @@ tauri-plugin-clipboard-manager = "2" [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" -[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] -tauri-plugin-updater = "2" - [dev-dependencies] tempfile = "3.24.0" diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json index ba6d080..3069583 100644 --- a/src-tauri/capabilities/desktop.json +++ b/src-tauri/capabilities/desktop.json @@ -9,6 +9,5 @@ "main" ], "permissions": [ - "updater:default" ] -} \ No newline at end of file +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a7a62b7..6010aca 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -21,7 +21,6 @@ pub mod ssh_tunnel; pub mod theme_commands; pub mod theme_models; pub mod task_manager; -pub mod updater; pub mod plugins; pub mod drivers { pub mod common; @@ -137,7 +136,6 @@ pub fn run() { .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_fs::init()) - .plugin(tauri_plugin_updater::Builder::new().build()) .manage(commands::QueryCancellationState::default()) .manage(export::ExportCancellationState::default()) .manage(dump_commands::DumpCancellationState::default()) @@ -284,10 +282,6 @@ pub fn run() { dump_commands::import_database, dump_commands::cancel_import, dump_commands::cancel_dump, - // Updater - updater::check_for_updates, - updater::download_and_install_update, - updater::get_installation_source, // Logs log_commands::get_logs, log_commands::clear_logs, diff --git a/src-tauri/src/updater.rs b/src-tauri/src/updater.rs deleted file mode 100644 index 6351f27..0000000 --- a/src-tauri/src/updater.rs +++ /dev/null @@ -1,435 +0,0 @@ -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::PathBuf; -use std::time::{SystemTime, UNIX_EPOCH}; -use tauri::Emitter; -use tauri::{AppHandle, Manager}; - -// Strutture dati -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct UpdateCheckResult { - pub has_update: bool, - pub current_version: String, - pub latest_version: String, - pub release_notes: String, - pub release_url: String, - pub published_at: String, - pub download_urls: Vec<DownloadAsset>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct DownloadAsset { - pub name: String, - pub url: String, - pub size: u64, - pub platform: String, -} - -// Cache structure -#[derive(Serialize, Deserialize, Debug, Clone)] -struct UpdateCheckCache { - last_checked: u64, - last_result: Option<UpdateCheckResult>, -} - -// GitHub API response -#[derive(Deserialize, Debug)] -struct GitHubRelease { - tag_name: String, - body: String, - html_url: String, - published_at: String, - assets: Vec<GitHubAsset>, -} - -#[derive(Deserialize, Debug)] -struct GitHubAsset { - name: String, - browser_download_url: String, - size: u64, -} - -// Constants -const GITHUB_REPO: &str = "debba/tabularis"; -const CACHE_DURATION_SECS: u64 = 43200; // 12 hours -/// Returns the installation source: "snap", "aur", or None for direct installs. -/// Only meaningful on Linux; always returns None on other platforms. -fn detect_installation_source() -> Option<String> { - #[cfg(target_os = "linux")] - { - // Snap sets the SNAP env var when running inside a snap sandbox - if std::env::var("SNAP").is_ok() { - return Some("snap".to_string()); - } - - // Flatpak sets FLATPAK_ID when running inside a Flatpak sandbox - if std::env::var("FLATPAK_ID").is_ok() { - return Some("flatpak".to_string()); - } - - // AUR: check if pacman's local database has a tabularis-bin entry - if let Ok(entries) = std::fs::read_dir("/var/lib/pacman/local") { - let is_aur = entries - .filter_map(|e| e.ok()) - .any(|e| e.file_name().to_string_lossy().starts_with("tabularis-bin-")); - if is_aur { - return Some("aur".to_string()); - } - } - } - - None -} - -/// Returns true when updates should not be managed by the app itself. -fn is_managed_package() -> bool { - detect_installation_source().is_some() -} - -#[tauri::command] -pub fn get_installation_source() -> Option<String> { - detect_installation_source() -} - -// Helper functions -fn get_cache_path(app: &AppHandle) -> Option<PathBuf> { - app.path() - .app_config_dir() - .ok() - .map(|p| p.join("update_check_cache.json")) -} - -fn parse_version(version: &str) -> Option<(u32, u32, u32)> { - let clean = version.trim_start_matches('v'); - let parts: Vec<&str> = clean.split('.').collect(); - if parts.len() != 3 { - return None; - } - - let major = parts[0].parse().ok()?; - let minor = parts[1].parse().ok()?; - let patch = parts[2].parse().ok()?; - - Some((major, minor, patch)) -} - -fn is_newer_version(current: &str, latest: &str) -> bool { - match (parse_version(current), parse_version(latest)) { - (Some(c), Some(l)) => l > c, - _ => false, - } -} - -async fn fetch_latest_release() -> Result<GitHubRelease, String> { - let client = Client::new(); - let url = format!( - "https://api.github.com/repos/{}/releases/latest", - GITHUB_REPO - ); - - let res = client - .get(&url) - .header("User-Agent", "Tabularis") - .header("Accept", "application/vnd.github.v3+json") - .send() - .await - .map_err(|e| format!("Network error: {}", e))?; - - if !res.status().is_success() { - return Err(format!("GitHub API error: {}", res.status())); - } - - res.json::<GitHubRelease>() - .await - .map_err(|e| format!("Failed to parse response: {}", e)) -} - -fn categorize_asset(name: &str) -> String { - if name.ends_with(".dmg") || name.contains("darwin") || name.contains("macos") { - "macos".to_string() - } else if name.ends_with(".exe") || name.ends_with(".msi") || name.contains("windows") { - "windows".to_string() - } else if name.ends_with(".AppImage") || name.ends_with(".deb") || name.ends_with(".rpm") { - "linux".to_string() - } else { - "other".to_string() - } -} - -// Tauri commands -#[tauri::command] -pub async fn check_for_updates(app: AppHandle, force: bool) -> Result<UpdateCheckResult, String> { - // Managed packages (AUR, Snap) should not use the built-in updater - if is_managed_package() { - return Err("Updates are managed by the package manager".to_string()); - } - - let config = crate::config::load_config_internal(&app); - - // Check if updates are disabled - if !force && config.check_for_updates == Some(false) { - return Err("Update checks disabled".to_string()); - } - - // Check cache if not forced - if !force { - if let Some(cache_path) = get_cache_path(&app) { - if cache_path.exists() { - if let Ok(content) = fs::read_to_string(&cache_path) { - if let Ok(cache) = serde_json::from_str::<UpdateCheckCache>(&content) { - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_secs(); - - if now - cache.last_checked < CACHE_DURATION_SECS { - if let Some(result) = cache.last_result { - // Invalidate cache if the app was updated since it was written - if result.current_version == env!("CARGO_PKG_VERSION") { - return Ok(result); - } - } - } - } - } - } - } - } - - // Fetch latest release from GitHub - let release = fetch_latest_release().await?; - - let current_version = env!("CARGO_PKG_VERSION"); - let latest_version = release.tag_name.trim_start_matches('v'); - - let download_urls = release - .assets - .into_iter() - .map(|asset| DownloadAsset { - name: asset.name.clone(), - url: asset.browser_download_url, - size: asset.size, - platform: categorize_asset(&asset.name), - }) - .collect(); - - let result = UpdateCheckResult { - has_update: is_newer_version(current_version, &release.tag_name), - current_version: current_version.to_string(), - latest_version: latest_version.to_string(), - release_notes: release.body, - release_url: release.html_url, - published_at: release.published_at, - download_urls, - }; - - // Save to cache - if let Some(cache_path) = get_cache_path(&app) { - let timestamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_secs(); - - let cache = UpdateCheckCache { - last_checked: timestamp, - last_result: Some(result.clone()), - }; - - if let Ok(content) = serde_json::to_string(&cache) { - let _ = fs::write(cache_path, content); - } - } - - Ok(result) -} - -#[tauri::command] -pub async fn download_and_install_update(app: AppHandle) -> Result<(), String> { - // Usa tauri-plugin-updater per gestire il download e installazione - use tauri_plugin_updater::UpdaterExt; - - let updater = app.updater_builder().build().map_err(|e| e.to_string())?; - - if let Some(update) = updater.check().await.map_err(|e| e.to_string())? { - // Emetti eventi per aggiornare la UI sul progresso - let mut downloaded = 0; - - update - .download_and_install( - |chunk_length, content_length| { - downloaded += chunk_length; - let progress = if let Some(total) = content_length { - (downloaded as f64 / total as f64 * 100.0) as u32 - } else { - 0 - }; - - let _ = app.emit("update-progress", progress); - }, - || { - // Pre-installazione: salva stato, chiudi connessioni, etc. - let _ = app.emit("update-installing", ()); - }, - ) - .await - .map_err(|e| e.to_string())?; - - app.restart(); - } else { - Err("No update available".to_string()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // Version parsing tests - #[test] - fn test_version_parsing_standard() { - assert_eq!(parse_version("0.8.8"), Some((0, 8, 8))); - assert_eq!(parse_version("1.2.3"), Some((1, 2, 3))); - assert_eq!(parse_version("10.20.30"), Some((10, 20, 30))); - } - - #[test] - fn test_version_parsing_with_v_prefix() { - assert_eq!(parse_version("v0.8.8"), Some((0, 8, 8))); - assert_eq!(parse_version("v1.0.0"), Some((1, 0, 0))); - } - - #[test] - fn test_version_parsing_invalid() { - assert_eq!(parse_version("invalid"), None); - assert_eq!(parse_version("1.2"), None); - assert_eq!(parse_version("1.2.3.4"), None); - assert_eq!(parse_version("a.b.c"), None); - assert_eq!(parse_version(""), None); - } - - #[test] - fn test_version_parsing_edge_cases() { - assert_eq!(parse_version("0.0.0"), Some((0, 0, 0))); - assert_eq!(parse_version("999.999.999"), Some((999, 999, 999))); - } - - // Version comparison tests - #[test] - fn test_version_comparison_newer() { - assert!(is_newer_version("0.8.8", "0.9.0")); - assert!(is_newer_version("0.8.8", "0.8.9")); - assert!(is_newer_version("0.8.8", "1.0.0")); - assert!(is_newer_version("1.0.0", "2.0.0")); - } - - #[test] - fn test_version_comparison_not_newer() { - assert!(!is_newer_version("0.8.8", "0.8.8")); - assert!(!is_newer_version("0.8.8", "0.8.7")); - assert!(!is_newer_version("0.8.8", "0.7.9")); - assert!(!is_newer_version("1.0.0", "0.9.9")); - } - - #[test] - fn test_version_comparison_with_v_prefix() { - assert!(is_newer_version("0.8.8", "v0.9.0")); - assert!(is_newer_version("v0.8.8", "0.9.0")); - assert!(is_newer_version("v0.8.8", "v0.9.0")); - } - - #[test] - fn test_version_comparison_invalid() { - assert!(!is_newer_version("invalid", "0.9.0")); - assert!(!is_newer_version("0.8.8", "invalid")); - assert!(!is_newer_version("invalid", "invalid")); - } - - // Asset categorization tests - #[test] - fn test_categorize_asset_macos() { - assert_eq!(categorize_asset("Tabularis_0.8.8_x64.dmg"), "macos"); - assert_eq!(categorize_asset("Tabularis_0.8.8_aarch64.dmg"), "macos"); - assert_eq!(categorize_asset("tabularis-darwin.zip"), "macos"); - assert_eq!(categorize_asset("app-macos-universal.tar.gz"), "macos"); - } - - #[test] - fn test_categorize_asset_windows() { - assert_eq!(categorize_asset("Tabularis_0.8.8_x64_setup.exe"), "windows"); - assert_eq!(categorize_asset("tabularis.msi"), "windows"); - assert_eq!(categorize_asset("app-windows-x86_64.zip"), "windows"); - } - - #[test] - fn test_categorize_asset_linux() { - assert_eq!(categorize_asset("tabularis_0.8.8_amd64.AppImage"), "linux"); - assert_eq!(categorize_asset("tabularis_0.8.8_amd64.deb"), "linux"); - assert_eq!(categorize_asset("tabularis-0.8.8-1.x86_64.rpm"), "linux"); - } - - #[test] - fn test_categorize_asset_other() { - assert_eq!(categorize_asset("README.txt"), "other"); - assert_eq!(categorize_asset("checksums.sha256"), "other"); - assert_eq!(categorize_asset("unknown-file"), "other"); - } - - // Cache path tests - #[test] - fn test_cache_filename() { - let expected = "update_check_cache.json"; - assert!(expected.ends_with(".json")); - assert!(expected.contains("cache")); - } - - // GitHub repo constant test - #[test] - fn test_github_repo_constant() { - assert_eq!(GITHUB_REPO, "debba/tabularis"); - } - - // Cache duration test - #[test] - fn test_cache_duration() { - assert_eq!(CACHE_DURATION_SECS, 43200); // 12 hours in seconds - assert_eq!(CACHE_DURATION_SECS / 3600, 12); // Verify it's 12 hours - } - - // Mutex to serialize env var mutations across parallel tests - static ENV_MUTEX: std::sync::LazyLock<std::sync::Mutex<()>> = - std::sync::LazyLock::new(|| std::sync::Mutex::new(())); - - // Installation source detection tests - #[test] - fn test_detect_installation_source_snap() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("FLATPAK_ID"); - std::env::set_var("SNAP", "/snap/tabularis/current"); - let source = detect_installation_source(); - std::env::remove_var("SNAP"); - assert_eq!(source.as_deref(), Some("snap")); - } - - #[test] - fn test_detect_installation_source_flatpak() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("SNAP"); - std::env::set_var("FLATPAK_ID", "io.github.debba.tabularis"); - let source = detect_installation_source(); - std::env::remove_var("FLATPAK_ID"); - assert_eq!(source.as_deref(), Some("flatpak")); - } - - #[test] - fn test_detect_installation_source_direct() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("SNAP"); - std::env::remove_var("FLATPAK_ID"); - let source = detect_installation_source(); - // On a dev/CI machine without pacman or tabularis-bin installed, must be None - assert!(source.is_none() || source.as_deref() == Some("aur")); - } -} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 86395be..4fbab47 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -23,38 +23,5 @@ "security": { "csp": null } - }, - "bundle": { - "createUpdaterArtifacts": true, - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/64x64.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "linux": { - "deb": { - "depends": [ - "libwebkit2gtk-4.1-0", - "libsecret-1-0" - ] - }, - "appimage": { - "bundleMediaFramework": false - } - } - }, - "plugins": { - "updater": { - "endpoints": [ - "https://github.com/debba/tabularis/releases/latest/download/latest.json" - ], - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDY0NzY0QjNEQjI4QjFEQjcKUldTM0hZdXlQVXQyWkRYdmRJOEJhVEpYTit2VXRYS0drTit1bmthSHVzcWlQK09Wb2l5cVpOWXAK" - } } -} \ No newline at end of file +} pkgs/by-name/ta/tabularis/package.nix 0 → 100644 +76 −0 Original line number Diff line number Diff line { lib, stdenv, rustPlatform, fetchFromGitHub, fetchPnpmDeps, cargo-tauri, nodejs, pnpm, pnpmConfigHook, wrapGAppsHook4, webkitgtk_4_1, pkg-config, openssl, nix-update-script, }: rustPlatform.buildRustPackage (finalAttrs: { pname = "tabularis"; version = "0.9.12"; src = fetchFromGitHub { owner = "debba"; repo = "tabularis"; tag = "v${finalAttrs.version}"; hash = "sha256-kObjJ+C+0d/wLNt902yUPe8Cvss8d0ILeuo98vIiYDU="; }; patches = [ ./disable-updater.patch ]; strictDeps = true; cargoRoot = "src-tauri"; buildAndTestSubdir = finalAttrs.cargoRoot; cargoHash = "sha256-XYvwgZMJXM62kC8+DR06LygtTnL+8TLWyRZAgTQWf3Q="; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; fetcherVersion = 3; hash = "sha256-S/XCypKyYlJtuISNiG8NtJzisAejiUwqPVltXEmVlZw="; }; nativeBuildInputs = [ cargo-tauri.hook nodejs pnpmConfigHook pnpm pkg-config ] ++ lib.optionals stdenv.hostPlatform.isLinux [ wrapGAppsHook4 ]; buildInputs = [ openssl ] ++ lib.optionals stdenv.hostPlatform.isLinux [ webkitgtk_4_1 ]; env.OPENSSL_NO_VENDOR = 1; passthru.updateScript = nix-update-script { }; meta = { description = "Lightweight, developer-focused database management tool, built with Tauri and React"; homepage = "http://tabularis.dev"; changelog = "https://github.com/debba/tabularis/blob/${finalAttrs.src.tag}/CHANGELOG.md"; license = lib.licenses.mit; inherit (cargo-tauri.hook.meta) platforms; maintainers = with lib.maintainers; [ nartsiss ]; mainProgram = "tabularis"; }; }) Loading
pkgs/by-name/ta/tabularis/disable-updater.patch 0 → 100644 +543 −0 Original line number Diff line number Diff line diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e74f8c5..5333b4a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -59,8 +59,5 @@ tauri-plugin-clipboard-manager = "2" [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" -[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] -tauri-plugin-updater = "2" - [dev-dependencies] tempfile = "3.24.0" diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json index ba6d080..3069583 100644 --- a/src-tauri/capabilities/desktop.json +++ b/src-tauri/capabilities/desktop.json @@ -9,6 +9,5 @@ "main" ], "permissions": [ - "updater:default" ] -} \ No newline at end of file +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a7a62b7..6010aca 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -21,7 +21,6 @@ pub mod ssh_tunnel; pub mod theme_commands; pub mod theme_models; pub mod task_manager; -pub mod updater; pub mod plugins; pub mod drivers { pub mod common; @@ -137,7 +136,6 @@ pub fn run() { .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_fs::init()) - .plugin(tauri_plugin_updater::Builder::new().build()) .manage(commands::QueryCancellationState::default()) .manage(export::ExportCancellationState::default()) .manage(dump_commands::DumpCancellationState::default()) @@ -284,10 +282,6 @@ pub fn run() { dump_commands::import_database, dump_commands::cancel_import, dump_commands::cancel_dump, - // Updater - updater::check_for_updates, - updater::download_and_install_update, - updater::get_installation_source, // Logs log_commands::get_logs, log_commands::clear_logs, diff --git a/src-tauri/src/updater.rs b/src-tauri/src/updater.rs deleted file mode 100644 index 6351f27..0000000 --- a/src-tauri/src/updater.rs +++ /dev/null @@ -1,435 +0,0 @@ -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::PathBuf; -use std::time::{SystemTime, UNIX_EPOCH}; -use tauri::Emitter; -use tauri::{AppHandle, Manager}; - -// Strutture dati -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct UpdateCheckResult { - pub has_update: bool, - pub current_version: String, - pub latest_version: String, - pub release_notes: String, - pub release_url: String, - pub published_at: String, - pub download_urls: Vec<DownloadAsset>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct DownloadAsset { - pub name: String, - pub url: String, - pub size: u64, - pub platform: String, -} - -// Cache structure -#[derive(Serialize, Deserialize, Debug, Clone)] -struct UpdateCheckCache { - last_checked: u64, - last_result: Option<UpdateCheckResult>, -} - -// GitHub API response -#[derive(Deserialize, Debug)] -struct GitHubRelease { - tag_name: String, - body: String, - html_url: String, - published_at: String, - assets: Vec<GitHubAsset>, -} - -#[derive(Deserialize, Debug)] -struct GitHubAsset { - name: String, - browser_download_url: String, - size: u64, -} - -// Constants -const GITHUB_REPO: &str = "debba/tabularis"; -const CACHE_DURATION_SECS: u64 = 43200; // 12 hours -/// Returns the installation source: "snap", "aur", or None for direct installs. -/// Only meaningful on Linux; always returns None on other platforms. -fn detect_installation_source() -> Option<String> { - #[cfg(target_os = "linux")] - { - // Snap sets the SNAP env var when running inside a snap sandbox - if std::env::var("SNAP").is_ok() { - return Some("snap".to_string()); - } - - // Flatpak sets FLATPAK_ID when running inside a Flatpak sandbox - if std::env::var("FLATPAK_ID").is_ok() { - return Some("flatpak".to_string()); - } - - // AUR: check if pacman's local database has a tabularis-bin entry - if let Ok(entries) = std::fs::read_dir("/var/lib/pacman/local") { - let is_aur = entries - .filter_map(|e| e.ok()) - .any(|e| e.file_name().to_string_lossy().starts_with("tabularis-bin-")); - if is_aur { - return Some("aur".to_string()); - } - } - } - - None -} - -/// Returns true when updates should not be managed by the app itself. -fn is_managed_package() -> bool { - detect_installation_source().is_some() -} - -#[tauri::command] -pub fn get_installation_source() -> Option<String> { - detect_installation_source() -} - -// Helper functions -fn get_cache_path(app: &AppHandle) -> Option<PathBuf> { - app.path() - .app_config_dir() - .ok() - .map(|p| p.join("update_check_cache.json")) -} - -fn parse_version(version: &str) -> Option<(u32, u32, u32)> { - let clean = version.trim_start_matches('v'); - let parts: Vec<&str> = clean.split('.').collect(); - if parts.len() != 3 { - return None; - } - - let major = parts[0].parse().ok()?; - let minor = parts[1].parse().ok()?; - let patch = parts[2].parse().ok()?; - - Some((major, minor, patch)) -} - -fn is_newer_version(current: &str, latest: &str) -> bool { - match (parse_version(current), parse_version(latest)) { - (Some(c), Some(l)) => l > c, - _ => false, - } -} - -async fn fetch_latest_release() -> Result<GitHubRelease, String> { - let client = Client::new(); - let url = format!( - "https://api.github.com/repos/{}/releases/latest", - GITHUB_REPO - ); - - let res = client - .get(&url) - .header("User-Agent", "Tabularis") - .header("Accept", "application/vnd.github.v3+json") - .send() - .await - .map_err(|e| format!("Network error: {}", e))?; - - if !res.status().is_success() { - return Err(format!("GitHub API error: {}", res.status())); - } - - res.json::<GitHubRelease>() - .await - .map_err(|e| format!("Failed to parse response: {}", e)) -} - -fn categorize_asset(name: &str) -> String { - if name.ends_with(".dmg") || name.contains("darwin") || name.contains("macos") { - "macos".to_string() - } else if name.ends_with(".exe") || name.ends_with(".msi") || name.contains("windows") { - "windows".to_string() - } else if name.ends_with(".AppImage") || name.ends_with(".deb") || name.ends_with(".rpm") { - "linux".to_string() - } else { - "other".to_string() - } -} - -// Tauri commands -#[tauri::command] -pub async fn check_for_updates(app: AppHandle, force: bool) -> Result<UpdateCheckResult, String> { - // Managed packages (AUR, Snap) should not use the built-in updater - if is_managed_package() { - return Err("Updates are managed by the package manager".to_string()); - } - - let config = crate::config::load_config_internal(&app); - - // Check if updates are disabled - if !force && config.check_for_updates == Some(false) { - return Err("Update checks disabled".to_string()); - } - - // Check cache if not forced - if !force { - if let Some(cache_path) = get_cache_path(&app) { - if cache_path.exists() { - if let Ok(content) = fs::read_to_string(&cache_path) { - if let Ok(cache) = serde_json::from_str::<UpdateCheckCache>(&content) { - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_secs(); - - if now - cache.last_checked < CACHE_DURATION_SECS { - if let Some(result) = cache.last_result { - // Invalidate cache if the app was updated since it was written - if result.current_version == env!("CARGO_PKG_VERSION") { - return Ok(result); - } - } - } - } - } - } - } - } - - // Fetch latest release from GitHub - let release = fetch_latest_release().await?; - - let current_version = env!("CARGO_PKG_VERSION"); - let latest_version = release.tag_name.trim_start_matches('v'); - - let download_urls = release - .assets - .into_iter() - .map(|asset| DownloadAsset { - name: asset.name.clone(), - url: asset.browser_download_url, - size: asset.size, - platform: categorize_asset(&asset.name), - }) - .collect(); - - let result = UpdateCheckResult { - has_update: is_newer_version(current_version, &release.tag_name), - current_version: current_version.to_string(), - latest_version: latest_version.to_string(), - release_notes: release.body, - release_url: release.html_url, - published_at: release.published_at, - download_urls, - }; - - // Save to cache - if let Some(cache_path) = get_cache_path(&app) { - let timestamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_secs(); - - let cache = UpdateCheckCache { - last_checked: timestamp, - last_result: Some(result.clone()), - }; - - if let Ok(content) = serde_json::to_string(&cache) { - let _ = fs::write(cache_path, content); - } - } - - Ok(result) -} - -#[tauri::command] -pub async fn download_and_install_update(app: AppHandle) -> Result<(), String> { - // Usa tauri-plugin-updater per gestire il download e installazione - use tauri_plugin_updater::UpdaterExt; - - let updater = app.updater_builder().build().map_err(|e| e.to_string())?; - - if let Some(update) = updater.check().await.map_err(|e| e.to_string())? { - // Emetti eventi per aggiornare la UI sul progresso - let mut downloaded = 0; - - update - .download_and_install( - |chunk_length, content_length| { - downloaded += chunk_length; - let progress = if let Some(total) = content_length { - (downloaded as f64 / total as f64 * 100.0) as u32 - } else { - 0 - }; - - let _ = app.emit("update-progress", progress); - }, - || { - // Pre-installazione: salva stato, chiudi connessioni, etc. - let _ = app.emit("update-installing", ()); - }, - ) - .await - .map_err(|e| e.to_string())?; - - app.restart(); - } else { - Err("No update available".to_string()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // Version parsing tests - #[test] - fn test_version_parsing_standard() { - assert_eq!(parse_version("0.8.8"), Some((0, 8, 8))); - assert_eq!(parse_version("1.2.3"), Some((1, 2, 3))); - assert_eq!(parse_version("10.20.30"), Some((10, 20, 30))); - } - - #[test] - fn test_version_parsing_with_v_prefix() { - assert_eq!(parse_version("v0.8.8"), Some((0, 8, 8))); - assert_eq!(parse_version("v1.0.0"), Some((1, 0, 0))); - } - - #[test] - fn test_version_parsing_invalid() { - assert_eq!(parse_version("invalid"), None); - assert_eq!(parse_version("1.2"), None); - assert_eq!(parse_version("1.2.3.4"), None); - assert_eq!(parse_version("a.b.c"), None); - assert_eq!(parse_version(""), None); - } - - #[test] - fn test_version_parsing_edge_cases() { - assert_eq!(parse_version("0.0.0"), Some((0, 0, 0))); - assert_eq!(parse_version("999.999.999"), Some((999, 999, 999))); - } - - // Version comparison tests - #[test] - fn test_version_comparison_newer() { - assert!(is_newer_version("0.8.8", "0.9.0")); - assert!(is_newer_version("0.8.8", "0.8.9")); - assert!(is_newer_version("0.8.8", "1.0.0")); - assert!(is_newer_version("1.0.0", "2.0.0")); - } - - #[test] - fn test_version_comparison_not_newer() { - assert!(!is_newer_version("0.8.8", "0.8.8")); - assert!(!is_newer_version("0.8.8", "0.8.7")); - assert!(!is_newer_version("0.8.8", "0.7.9")); - assert!(!is_newer_version("1.0.0", "0.9.9")); - } - - #[test] - fn test_version_comparison_with_v_prefix() { - assert!(is_newer_version("0.8.8", "v0.9.0")); - assert!(is_newer_version("v0.8.8", "0.9.0")); - assert!(is_newer_version("v0.8.8", "v0.9.0")); - } - - #[test] - fn test_version_comparison_invalid() { - assert!(!is_newer_version("invalid", "0.9.0")); - assert!(!is_newer_version("0.8.8", "invalid")); - assert!(!is_newer_version("invalid", "invalid")); - } - - // Asset categorization tests - #[test] - fn test_categorize_asset_macos() { - assert_eq!(categorize_asset("Tabularis_0.8.8_x64.dmg"), "macos"); - assert_eq!(categorize_asset("Tabularis_0.8.8_aarch64.dmg"), "macos"); - assert_eq!(categorize_asset("tabularis-darwin.zip"), "macos"); - assert_eq!(categorize_asset("app-macos-universal.tar.gz"), "macos"); - } - - #[test] - fn test_categorize_asset_windows() { - assert_eq!(categorize_asset("Tabularis_0.8.8_x64_setup.exe"), "windows"); - assert_eq!(categorize_asset("tabularis.msi"), "windows"); - assert_eq!(categorize_asset("app-windows-x86_64.zip"), "windows"); - } - - #[test] - fn test_categorize_asset_linux() { - assert_eq!(categorize_asset("tabularis_0.8.8_amd64.AppImage"), "linux"); - assert_eq!(categorize_asset("tabularis_0.8.8_amd64.deb"), "linux"); - assert_eq!(categorize_asset("tabularis-0.8.8-1.x86_64.rpm"), "linux"); - } - - #[test] - fn test_categorize_asset_other() { - assert_eq!(categorize_asset("README.txt"), "other"); - assert_eq!(categorize_asset("checksums.sha256"), "other"); - assert_eq!(categorize_asset("unknown-file"), "other"); - } - - // Cache path tests - #[test] - fn test_cache_filename() { - let expected = "update_check_cache.json"; - assert!(expected.ends_with(".json")); - assert!(expected.contains("cache")); - } - - // GitHub repo constant test - #[test] - fn test_github_repo_constant() { - assert_eq!(GITHUB_REPO, "debba/tabularis"); - } - - // Cache duration test - #[test] - fn test_cache_duration() { - assert_eq!(CACHE_DURATION_SECS, 43200); // 12 hours in seconds - assert_eq!(CACHE_DURATION_SECS / 3600, 12); // Verify it's 12 hours - } - - // Mutex to serialize env var mutations across parallel tests - static ENV_MUTEX: std::sync::LazyLock<std::sync::Mutex<()>> = - std::sync::LazyLock::new(|| std::sync::Mutex::new(())); - - // Installation source detection tests - #[test] - fn test_detect_installation_source_snap() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("FLATPAK_ID"); - std::env::set_var("SNAP", "/snap/tabularis/current"); - let source = detect_installation_source(); - std::env::remove_var("SNAP"); - assert_eq!(source.as_deref(), Some("snap")); - } - - #[test] - fn test_detect_installation_source_flatpak() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("SNAP"); - std::env::set_var("FLATPAK_ID", "io.github.debba.tabularis"); - let source = detect_installation_source(); - std::env::remove_var("FLATPAK_ID"); - assert_eq!(source.as_deref(), Some("flatpak")); - } - - #[test] - fn test_detect_installation_source_direct() { - let _lock = ENV_MUTEX.lock().unwrap(); - std::env::remove_var("SNAP"); - std::env::remove_var("FLATPAK_ID"); - let source = detect_installation_source(); - // On a dev/CI machine without pacman or tabularis-bin installed, must be None - assert!(source.is_none() || source.as_deref() == Some("aur")); - } -} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 86395be..4fbab47 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -23,38 +23,5 @@ "security": { "csp": null } - }, - "bundle": { - "createUpdaterArtifacts": true, - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/64x64.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "linux": { - "deb": { - "depends": [ - "libwebkit2gtk-4.1-0", - "libsecret-1-0" - ] - }, - "appimage": { - "bundleMediaFramework": false - } - } - }, - "plugins": { - "updater": { - "endpoints": [ - "https://github.com/debba/tabularis/releases/latest/download/latest.json" - ], - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDY0NzY0QjNEQjI4QjFEQjcKUldTM0hZdXlQVXQyWkRYdmRJOEJhVEpYTit2VXRYS0drTit1bmthSHVzcWlQK09Wb2l5cVpOWXAK" - } } -} \ No newline at end of file +}
pkgs/by-name/ta/tabularis/package.nix 0 → 100644 +76 −0 Original line number Diff line number Diff line { lib, stdenv, rustPlatform, fetchFromGitHub, fetchPnpmDeps, cargo-tauri, nodejs, pnpm, pnpmConfigHook, wrapGAppsHook4, webkitgtk_4_1, pkg-config, openssl, nix-update-script, }: rustPlatform.buildRustPackage (finalAttrs: { pname = "tabularis"; version = "0.9.12"; src = fetchFromGitHub { owner = "debba"; repo = "tabularis"; tag = "v${finalAttrs.version}"; hash = "sha256-kObjJ+C+0d/wLNt902yUPe8Cvss8d0ILeuo98vIiYDU="; }; patches = [ ./disable-updater.patch ]; strictDeps = true; cargoRoot = "src-tauri"; buildAndTestSubdir = finalAttrs.cargoRoot; cargoHash = "sha256-XYvwgZMJXM62kC8+DR06LygtTnL+8TLWyRZAgTQWf3Q="; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; fetcherVersion = 3; hash = "sha256-S/XCypKyYlJtuISNiG8NtJzisAejiUwqPVltXEmVlZw="; }; nativeBuildInputs = [ cargo-tauri.hook nodejs pnpmConfigHook pnpm pkg-config ] ++ lib.optionals stdenv.hostPlatform.isLinux [ wrapGAppsHook4 ]; buildInputs = [ openssl ] ++ lib.optionals stdenv.hostPlatform.isLinux [ webkitgtk_4_1 ]; env.OPENSSL_NO_VENDOR = 1; passthru.updateScript = nix-update-script { }; meta = { description = "Lightweight, developer-focused database management tool, built with Tauri and React"; homepage = "http://tabularis.dev"; changelog = "https://github.com/debba/tabularis/blob/${finalAttrs.src.tag}/CHANGELOG.md"; license = lib.licenses.mit; inherit (cargo-tauri.hook.meta) platforms; maintainers = with lib.maintainers; [ nartsiss ]; mainProgram = "tabularis"; }; })