From 8440daaedd472e34b6d778eb00bc44d98e0a2867 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 17 Jul 2023 10:27:12 +0200 Subject: [PATCH 1/6] added semver compatibility check for Windows and Linux --- Cargo.lock | 1 + Cargo.toml | 1 + plugins/single-instance/Cargo.toml | 1 + plugins/single-instance/src/lib.rs | 3 +++ .../single-instance/src/platform_impl/linux.rs | 13 ++++++++----- .../single-instance/src/platform_impl/windows.rs | 6 ++++-- plugins/single-instance/src/semver_compat.rs | 16 ++++++++++++++++ 7 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 plugins/single-instance/src/semver_compat.rs diff --git a/Cargo.lock b/Cargo.lock index 643a74370..917c054a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4555,6 +4555,7 @@ name = "tauri-plugin-single-instance" version = "0.0.0" dependencies = [ "log", + "semver 1.0.16", "serde", "serde_json", "tauri", diff --git a/Cargo.toml b/Cargo.toml index 94a7e79d8..702e4ffcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ serde = { version = "1", features = ["derive"] } log = "0.4" tauri = "1" tauri-build = "1" +semver = "1" serde_json = "1" thiserror = "1" diff --git a/plugins/single-instance/Cargo.toml b/plugins/single-instance/Cargo.toml index be46f3aa2..b7ef93a11 100644 --- a/plugins/single-instance/Cargo.toml +++ b/plugins/single-instance/Cargo.toml @@ -11,6 +11,7 @@ exclude = ["/examples"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +semver.workspace = true serde.workspace = true serde_json.workspace = true tauri.workspace = true diff --git a/plugins/single-instance/src/lib.rs b/plugins/single-instance/src/lib.rs index a2ff71afe..72360ed26 100644 --- a/plugins/single-instance/src/lib.rs +++ b/plugins/single-instance/src/lib.rs @@ -10,6 +10,9 @@ mod platform_impl; #[path = "platform_impl/macos.rs"] mod platform_impl; + +mod semver_compat; + pub(crate) type SingleInstanceCallback = dyn FnMut(&AppHandle, Vec, String) + Send + Sync + 'static; diff --git a/plugins/single-instance/src/platform_impl/linux.rs b/plugins/single-instance/src/platform_impl/linux.rs index 513526d44..601485a6e 100644 --- a/plugins/single-instance/src/platform_impl/linux.rs +++ b/plugins/single-instance/src/platform_impl/linux.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use crate::SingleInstanceCallback; +use crate::{SingleInstanceCallback, semver_compat::semver_compat_string}; use tauri::{ plugin::{self, TauriPlugin}, AppHandle, Config, Manager, RunEvent, Runtime, @@ -26,14 +26,17 @@ impl SingleInstanceDBus { } } -fn dbus_id(config: Arc) -> String { - config.tauri.bundle.identifier.replace(['.', '-'], "_") +fn dbus_id(config: Arc, version: semver::Version) -> String { + let mut id = config.tauri.bundle.identifier.replace(['.', '-'], "_"); + id.push('_'); + id.push_str(semver_compat_string(version).as_str()); + id } pub fn init(f: Box>) -> TauriPlugin { plugin::Builder::new("single-instance") .setup(|app| { - let id = dbus_id(app.config()); + let id = dbus_id(app.config(), app.package_info().version.clone()); let single_instance_dbus = SingleInstanceDBus { callback: f, app_handle: app.clone(), @@ -85,7 +88,7 @@ pub fn init(f: Box>) -> TauriPlugin { pub fn destroy>(manager: &M) { if let Some(connection) = manager.try_state::() { - let dbus_name = format!("org.{}.SingleInstance", dbus_id(manager.config())); + let dbus_name = format!("org.{}.SingleInstance", dbus_id(manager.config(), manager.app_handle().package_info().version.clone())); let _ = connection.0.release_name(dbus_name); } } diff --git a/plugins/single-instance/src/platform_impl/windows.rs b/plugins/single-instance/src/platform_impl/windows.rs index 5919d3e1a..3d977c975 100644 --- a/plugins/single-instance/src/platform_impl/windows.rs +++ b/plugins/single-instance/src/platform_impl/windows.rs @@ -1,6 +1,6 @@ #![cfg(target_os = "windows")] -use crate::SingleInstanceCallback; +use crate::{SingleInstanceCallback, semver_compat::semver_compat_string}; use std::ffi::CStr; use tauri::{ plugin::{self, TauriPlugin}, @@ -29,7 +29,9 @@ const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542; pub fn init(f: Box>) -> TauriPlugin { plugin::Builder::new("single-instance") .setup(|app| { - let id = &app.config().tauri.bundle.identifier; + let mut id = (&app.config().tauri.bundle.identifier).to_owned(); + id.push('_'); + id.push_str(semver_compat_string(app.package_info().version.clone()).as_str()); let class_name = encode_wide(format!("{id}-sic")); let window_name = encode_wide(format!("{id}-siw")); diff --git a/plugins/single-instance/src/semver_compat.rs b/plugins/single-instance/src/semver_compat.rs new file mode 100644 index 000000000..497db7387 --- /dev/null +++ b/plugins/single-instance/src/semver_compat.rs @@ -0,0 +1,16 @@ +/// Takes a version and spits out a String with trailing .x, thus only considering the digits +/// relevant regarding semver compatibility +pub fn semver_compat_string(version: semver::Version) -> String { + if version.pre.is_empty() == false { // for pre-release always treat each version separately + return version.to_string().replace(['.', '-'], "_") + } + match version.major { + 0 => { + match version.minor { + 0 => format!("0_0_{}", version.patch), + _ => format!("0_{}_x", version.minor), + } + }, + _ => format!("{}_x_x", version.major) + } +} \ No newline at end of file From 65037e7dcf8e354ff9445084fab738ad3fd695bb Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 17 Jul 2023 12:39:13 +0200 Subject: [PATCH 2/6] fixed formatting --- plugins/single-instance/src/lib.rs | 1 - .../src/platform_impl/linux.rs | 10 +++++-- .../src/platform_impl/windows.rs | 2 +- plugins/single-instance/src/semver_compat.rs | 27 +++++++++---------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/plugins/single-instance/src/lib.rs b/plugins/single-instance/src/lib.rs index 72360ed26..895cbc331 100644 --- a/plugins/single-instance/src/lib.rs +++ b/plugins/single-instance/src/lib.rs @@ -10,7 +10,6 @@ mod platform_impl; #[path = "platform_impl/macos.rs"] mod platform_impl; - mod semver_compat; pub(crate) type SingleInstanceCallback = diff --git a/plugins/single-instance/src/platform_impl/linux.rs b/plugins/single-instance/src/platform_impl/linux.rs index 601485a6e..fc082afea 100644 --- a/plugins/single-instance/src/platform_impl/linux.rs +++ b/plugins/single-instance/src/platform_impl/linux.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use crate::{SingleInstanceCallback, semver_compat::semver_compat_string}; +use crate::{semver_compat::semver_compat_string, SingleInstanceCallback}; use tauri::{ plugin::{self, TauriPlugin}, AppHandle, Config, Manager, RunEvent, Runtime, @@ -88,7 +88,13 @@ pub fn init(f: Box>) -> TauriPlugin { pub fn destroy>(manager: &M) { if let Some(connection) = manager.try_state::() { - let dbus_name = format!("org.{}.SingleInstance", dbus_id(manager.config(), manager.app_handle().package_info().version.clone())); + let dbus_name = format!( + "org.{}.SingleInstance", + dbus_id( + manager.config(), + manager.app_handle().package_info().version.clone() + ) + ); let _ = connection.0.release_name(dbus_name); } } diff --git a/plugins/single-instance/src/platform_impl/windows.rs b/plugins/single-instance/src/platform_impl/windows.rs index 3d977c975..24640c41e 100644 --- a/plugins/single-instance/src/platform_impl/windows.rs +++ b/plugins/single-instance/src/platform_impl/windows.rs @@ -1,6 +1,6 @@ #![cfg(target_os = "windows")] -use crate::{SingleInstanceCallback, semver_compat::semver_compat_string}; +use crate::{semver_compat::semver_compat_string, SingleInstanceCallback}; use std::ffi::CStr; use tauri::{ plugin::{self, TauriPlugin}, diff --git a/plugins/single-instance/src/semver_compat.rs b/plugins/single-instance/src/semver_compat.rs index 497db7387..32145afd5 100644 --- a/plugins/single-instance/src/semver_compat.rs +++ b/plugins/single-instance/src/semver_compat.rs @@ -1,16 +1,15 @@ -/// Takes a version and spits out a String with trailing .x, thus only considering the digits +/// Takes a version and spits out a String with trailing _x, thus only considering the digits /// relevant regarding semver compatibility pub fn semver_compat_string(version: semver::Version) -> String { - if version.pre.is_empty() == false { // for pre-release always treat each version separately - return version.to_string().replace(['.', '-'], "_") - } - match version.major { - 0 => { - match version.minor { - 0 => format!("0_0_{}", version.patch), - _ => format!("0_{}_x", version.minor), - } - }, - _ => format!("{}_x_x", version.major) - } -} \ No newline at end of file + // for pre-release always treat each version separately + if !version.pre.is_empty() { + return version.to_string().replace(['.', '-'], "_"); + } + match version.major { + 0 => match version.minor { + 0 => format!("0_0_{}", version.patch), + _ => format!("0_{}_x", version.minor), + }, + _ => format!("{}_x_x", version.major), + } +} From f13f6d58f5f09ac4e7e77a34004abc517d342720 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 28 Feb 2024 22:10:31 +0100 Subject: [PATCH 3/6] put semver feature behind a feature flag --- plugins/single-instance/Cargo.toml | 5 +++- plugins/single-instance/src/lib.rs | 1 + .../src/platform_impl/linux.rs | 28 +++++++++++++------ .../src/platform_impl/windows.rs | 17 +++++++---- plugins/single-instance/src/semver_compat.rs | 2 ++ 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/plugins/single-instance/Cargo.toml b/plugins/single-instance/Cargo.toml index b7ef93a11..c07cfc06d 100644 --- a/plugins/single-instance/Cargo.toml +++ b/plugins/single-instance/Cargo.toml @@ -11,12 +11,12 @@ exclude = ["/examples"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -semver.workspace = true serde.workspace = true serde_json.workspace = true tauri.workspace = true log.workspace = true thiserror.workspace = true +semver = { version = "1", optional = true } [target.'cfg(target_os = "windows")'.dependencies.windows-sys] version = "0.48" @@ -32,3 +32,6 @@ features = [ [target.'cfg(target_os = "linux")'.dependencies] zbus = "3" + +[features] +semver = ["dep:semver"] \ No newline at end of file diff --git a/plugins/single-instance/src/lib.rs b/plugins/single-instance/src/lib.rs index 895cbc331..365c77b47 100644 --- a/plugins/single-instance/src/lib.rs +++ b/plugins/single-instance/src/lib.rs @@ -10,6 +10,7 @@ mod platform_impl; #[path = "platform_impl/macos.rs"] mod platform_impl; +#[cfg(feature = "semver")] mod semver_compat; pub(crate) type SingleInstanceCallback = diff --git a/plugins/single-instance/src/platform_impl/linux.rs b/plugins/single-instance/src/platform_impl/linux.rs index fc082afea..f5a3e61de 100644 --- a/plugins/single-instance/src/platform_impl/linux.rs +++ b/plugins/single-instance/src/platform_impl/linux.rs @@ -2,7 +2,10 @@ use std::sync::Arc; -use crate::{semver_compat::semver_compat_string, SingleInstanceCallback}; +#[cfg(feature = "semver")] +use crate::semver_compat::semver_compat_string; + +use crate::SingleInstanceCallback; use tauri::{ plugin::{self, TauriPlugin}, AppHandle, Config, Manager, RunEvent, Runtime, @@ -26,6 +29,7 @@ impl SingleInstanceDBus { } } +#[cfg(feature = "semver")] fn dbus_id(config: Arc, version: semver::Version) -> String { let mut id = config.tauri.bundle.identifier.replace(['.', '-'], "_"); id.push('_'); @@ -33,10 +37,19 @@ fn dbus_id(config: Arc, version: semver::Version) -> String { id } +#[cfg(not(feature = "semver"))] +fn dbus_id(config: Arc) -> String { + config.tauri.bundle.identifier.replace(['.', '-'], "_") +} + pub fn init(f: Box>) -> TauriPlugin { plugin::Builder::new("single-instance") .setup(|app| { + #[cfg(feature = "semver")] let id = dbus_id(app.config(), app.package_info().version.clone()); + #[cfg(not(feature = "semver"))] + let id = dbus_id(app.config()); + let single_instance_dbus = SingleInstanceDBus { callback: f, app_handle: app.clone(), @@ -88,13 +101,12 @@ pub fn init(f: Box>) -> TauriPlugin { pub fn destroy>(manager: &M) { if let Some(connection) = manager.try_state::() { - let dbus_name = format!( - "org.{}.SingleInstance", - dbus_id( - manager.config(), - manager.app_handle().package_info().version.clone() - ) - ); + #[cfg(feature = "semver")] + let id = dbus_id(app.config(), app.package_info().version.clone()); + #[cfg(not(feature = "semver"))] + let id = dbus_id(app.config()); + + let dbus_name = format!("org.{id}.SingleInstance",); let _ = connection.0.release_name(dbus_name); } } diff --git a/plugins/single-instance/src/platform_impl/windows.rs b/plugins/single-instance/src/platform_impl/windows.rs index 24640c41e..bfdc00670 100644 --- a/plugins/single-instance/src/platform_impl/windows.rs +++ b/plugins/single-instance/src/platform_impl/windows.rs @@ -1,6 +1,9 @@ #![cfg(target_os = "windows")] -use crate::{semver_compat::semver_compat_string, SingleInstanceCallback}; +#[cfg(feature = "semver")] +use crate::semver_compat::semver_compat_string; + +use crate::SingleInstanceCallback; use std::ffi::CStr; use tauri::{ plugin::{self, TauriPlugin}, @@ -29,9 +32,13 @@ const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542; pub fn init(f: Box>) -> TauriPlugin { plugin::Builder::new("single-instance") .setup(|app| { - let mut id = (&app.config().tauri.bundle.identifier).to_owned(); - id.push('_'); - id.push_str(semver_compat_string(app.package_info().version.clone()).as_str()); + #[allow(unused_mut)] + let mut id = app.config().tauri.bundle.identifier.clone(); + #[cfg(feature = "semver")] + { + id.push('_'); + id.push_str(semver_compat_string(app.package_info().version.clone()).as_str()); + } let class_name = encode_wide(format!("{id}-sic")); let window_name = encode_wide(format!("{id}-siw")); @@ -117,7 +124,7 @@ unsafe extern "system" fn single_instance_window_proc( let data = CStr::from_ptr((*cds_ptr).lpData as _).to_string_lossy(); let mut s = data.split('|'); let cwd = s.next().unwrap(); - let args = s.into_iter().map(|s| s.to_string()).collect(); + let args = s.map(|s| s.to_string()).collect(); callback(app_handle, args, cwd.to_string()); } 1 diff --git a/plugins/single-instance/src/semver_compat.rs b/plugins/single-instance/src/semver_compat.rs index 32145afd5..287f52beb 100644 --- a/plugins/single-instance/src/semver_compat.rs +++ b/plugins/single-instance/src/semver_compat.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "semver")] + /// Takes a version and spits out a String with trailing _x, thus only considering the digits /// relevant regarding semver compatibility pub fn semver_compat_string(version: semver::Version) -> String { From 4139d6723fe321ad0b89f944f91bb7989092825b Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 28 Feb 2024 22:11:50 +0100 Subject: [PATCH 4/6] remove semver from root manifest --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 702e4ffcd..94a7e79d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ serde = { version = "1", features = ["derive"] } log = "0.4" tauri = "1" tauri-build = "1" -semver = "1" serde_json = "1" thiserror = "1" From e8986e22b95f73abbdc9068926ab9341a57cba6a Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Wed, 28 Feb 2024 23:03:57 +0100 Subject: [PATCH 5/6] linux compile error --- plugins/single-instance/src/platform_impl/linux.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/single-instance/src/platform_impl/linux.rs b/plugins/single-instance/src/platform_impl/linux.rs index f5a3e61de..2f4747db8 100644 --- a/plugins/single-instance/src/platform_impl/linux.rs +++ b/plugins/single-instance/src/platform_impl/linux.rs @@ -102,9 +102,12 @@ pub fn init(f: Box>) -> TauriPlugin { pub fn destroy>(manager: &M) { if let Some(connection) = manager.try_state::() { #[cfg(feature = "semver")] - let id = dbus_id(app.config(), app.package_info().version.clone()); + let id = dbus_id( + manager.config(), + manager.app_handle().package_info().version.clone(), + ); #[cfg(not(feature = "semver"))] - let id = dbus_id(app.config()); + let id = dbus_id(manager.config()); let dbus_name = format!("org.{id}.SingleInstance",); let _ = connection.0.release_name(dbus_name); From 74add7f7ecec463fec207473820682fab6d8b6b0 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Mon, 15 Apr 2024 15:50:38 +0200 Subject: [PATCH 6/6] docs: Add mention for semver feature in readme --- plugins/log/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/log/README.md b/plugins/log/README.md index 2d2e8534d..613103d39 100644 --- a/plugins/log/README.md +++ b/plugins/log/README.md @@ -21,7 +21,9 @@ Install the Core plugin by adding the following to your `Cargo.toml` file: tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } ``` -You can install the JavaScript Guest bindings using your preferred JavaScript package manager: +If you want the single instance mechanism to only trigger for semver compatible instances of your apps, for example if you expect users to have multiple installations of your app installed, you can add `features = ["semver"]` to the dependency declaration in `Cargo.toml`. + +Then you can install the JavaScript Guest bindings using your preferred JavaScript package manager: > Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.