auto_launch/
lib.rs

1//! Auto launch any application or executable at startup. Supports Windows, Mac (via AppleScript or Launch Agent), and Linux.
2//!
3//! ## Usage
4//!
5//! The parameters of `AutoLaunch::new` are different on each platform.
6//! See the function definition or the demo below for details.
7//!
8//! Or you can construct the AutoLaunch by using `AutoLaunchBuilder`.
9//!
10//! ```rust
11//! # #[cfg(target_os = "linux")]
12//! # mod linux {
13//! use auto_launch::AutoLaunch;
14//!
15//! fn main() {
16//!     let app_name = "the-app";
17//!     let app_path = "/path/to/the-app";
18//!     let args = &["--minimized"];
19//!     let auto = AutoLaunch::new(app_name, app_path, args);
20//!
21//!     // enable the auto launch
22//!     auto.enable().is_ok();
23//!     auto.is_enabled().unwrap();
24//!
25//!     // disable the auto launch
26//!     auto.disable().is_ok();
27//!     auto.is_enabled().unwrap();
28//! }
29//! # }
30//! ```
31//!
32//! ### macOS
33//!
34//! macOS supports two ways to achieve auto launch (via AppleScript or Launch Agent).
35//! When the `use_launch_agent` is true, it will achieve by Launch Agent, otherwise by AppleScript.
36//!
37//! **Note**:
38//! - The `app_path` should be a absolute path and exists. Otherwise, it will cause an error when `enable`.
39//! - In case using AppleScript, the `app_name` should be same as the basename of `app_path`, or it will be corrected automatically.
40//!
41//! ```rust
42//! # #[cfg(target_os = "macos")]
43//! # mod macos {
44//! use auto_launch::AutoLaunch;
45//!
46//! fn main() {
47//!     let app_name = "the-app";
48//!     let app_path = "/path/to/the-app.app";
49//!     let args = &["--minimized"];
50//!     let auto = AutoLaunch::new(app_name, app_path, false, args);
51//!
52//!     // enable the auto launch
53//!     auto.enable().is_ok();
54//!     auto.is_enabled().unwrap();
55//!
56//!     // disable the auto launch
57//!     auto.disable().is_ok();
58//!     auto.is_enabled().unwrap();
59//! }
60//! # }
61//! ```
62//!
63//! ### Windows
64//!
65//! On Windows, it will add a registry entry under `\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`.
66//!
67//! ```rust
68//! # #[cfg(target_os = "windows")]
69//! # mod win {
70//! use auto_launch::AutoLaunch;
71//!
72//! fn main() {
73//!     let app_name = "the-app";
74//!     let app_path = "C:\\path\\to\\the-app.exe";
75//!     let args = &["--minimized"];
76//!     let auto = AutoLaunch::new(app_name, app_path, args);
77//!
78//!     // enable the auto launch
79//!     auto.enable().is_ok();
80//!     auto.is_enabled().unwrap();
81//!
82//!     // disable the auto launch
83//!     auto.disable().is_ok();
84//!     auto.is_enabled().unwrap();
85//! }
86//! # }
87//! ```
88//!
89//! ### Builder
90//!
91//! AutoLaunch Builder helps to eliminate the constructor difference
92//! on various platforms.
93//!
94//! ```rust
95//! use auto_launch::*;
96//!
97//! fn main() {
98//!     let auto = AutoLaunchBuilder::new()
99//!         .set_app_name("the-app")
100//!         .set_app_path("/path/to/the-app")
101//!         .set_use_launch_agent(true)
102//!         .set_args(&["--minimized"])
103//!         .build()
104//!         .unwrap();
105//!
106//!     auto.enable().is_ok();
107//!     auto.is_enabled().unwrap();
108//!
109//!     auto.disable().is_ok();
110//!     auto.is_enabled().unwrap();
111//! }
112//! ```
113//!
114
115#[derive(thiserror::Error, Debug)]
116pub enum Error {
117    #[error("app_name shouldn't be None")]
118    AppNameNotSpecified,
119    #[error("app_path shouldn't be None")]
120    AppPathNotSpecified,
121    #[error("app path doesn't exist: {0}")]
122    AppPathDoesntExist(std::path::PathBuf),
123    #[error("app path is not absolute: {0}")]
124    AppPathIsNotAbsolute(std::path::PathBuf),
125    #[error("Failed to execute apple script with status: {0}")]
126    AppleScriptFailed(i32),
127    #[error("Unsupported target os")]
128    UnsupportedOS,
129    #[error(transparent)]
130    Io(#[from] std::io::Error),
131}
132
133pub type Result<T> = std::result::Result<T, Error>;
134
135#[cfg(target_os = "linux")]
136mod linux;
137#[cfg(target_os = "macos")]
138mod macos;
139#[cfg(target_os = "windows")]
140mod windows;
141
142/// The parameters of `AutoLaunch::new` are different on each platform.
143///
144/// ### Linux
145///
146/// ```rust
147/// # #[cfg(target_os = "linux")]
148/// # {
149/// # use auto_launch::AutoLaunch;
150/// # let app_name = "the-app";
151/// # let app_path = "/path/to/the-app";
152/// # let args = &["--minimized"];
153/// AutoLaunch::new(app_name, app_path, args);
154/// # }
155/// ```
156///
157/// ### Macos
158///
159/// ```rust
160/// # #[cfg(target_os = "macos")]
161/// # {
162/// # use auto_launch::AutoLaunch;
163/// # let app_name = "the-app";
164/// # let app_path = "/path/to/the-app";
165/// # let use_launch_agent = false;
166/// # let args = &["--minimized"];
167/// AutoLaunch::new(app_name, app_path, use_launch_agent, args);
168/// # }
169/// ```
170///
171/// ### Windows
172///
173/// ```rust
174/// # #[cfg(target_os = "windows")]
175/// # {
176/// # use auto_launch::AutoLaunch;
177/// # let app_name = "the-app";
178/// # let app_path = "/path/to/the-app";
179/// # let args = &["--minimized"];
180/// AutoLaunch::new(app_name, app_path, args);
181/// # }
182/// ```
183#[derive(Debug, Clone, PartialEq, Eq)]
184pub struct AutoLaunch {
185    /// The application name
186    pub(crate) app_name: String,
187
188    /// The application executable path (absolute path will be better)
189    pub(crate) app_path: String,
190
191    #[cfg(target_os = "macos")]
192    /// Whether use Launch Agent for implement or use AppleScript
193    pub(crate) use_launch_agent: bool,
194
195    /// Args passed to the binary on startup
196    pub(crate) args: Vec<String>,
197}
198
199impl AutoLaunch {
200    /// check whether it is support the platform
201    ///
202    /// ## Usage
203    ///
204    /// ```rust
205    /// use auto_launch::AutoLaunch;
206    ///
207    /// dbg!(AutoLaunch::is_support());
208    /// ```
209    pub fn is_support() -> bool {
210        cfg!(any(
211            target_os = "linux",
212            target_os = "macos",
213            target_os = "windows",
214        ))
215    }
216
217    /// get the application name
218    pub fn get_app_name(&self) -> &str {
219        &self.app_name
220    }
221
222    /// get the application path
223    pub fn get_app_path(&self) -> &str {
224        &self.app_path
225    }
226
227    /// get the args
228    pub fn get_args(&self) -> &[String] {
229        &self.args
230    }
231}
232
233#[derive(Debug, Default, Clone)]
234/// AutoLaunch Builder helps to eliminate the constructor difference
235/// on various platforms.
236///
237/// ## Notes
238///
239/// The builder will not check whether the app_path matches the platform-specify file path.
240///
241/// ## Usage
242///
243/// ```rust
244/// use auto_launch::*;
245///
246/// fn main() {
247///     let auto = AutoLaunchBuilder::new()
248///         .set_app_name("the-app")
249///         .set_app_path("/path/to/the-app")
250///         .set_use_launch_agent(true)
251///         .set_args(&["--minimized"])
252///         .build()
253///         .unwrap();
254///
255///     auto.enable().is_ok();
256///     auto.is_enabled().unwrap();
257///
258///     auto.disable().is_ok();
259///     auto.is_enabled().unwrap();
260/// }
261/// ```
262pub struct AutoLaunchBuilder {
263    pub app_name: Option<String>,
264
265    pub app_path: Option<String>,
266
267    pub use_launch_agent: bool,
268
269    pub args: Option<Vec<String>>,
270}
271
272impl AutoLaunchBuilder {
273    pub fn new() -> AutoLaunchBuilder {
274        AutoLaunchBuilder::default()
275    }
276
277    /// Set the `app_name`
278    pub fn set_app_name(&mut self, name: &str) -> &mut Self {
279        self.app_name = Some(name.into());
280        self
281    }
282
283    /// Set the `app_path`
284    pub fn set_app_path(&mut self, path: &str) -> &mut Self {
285        self.app_path = Some(path.into());
286        self
287    }
288
289    /// Set the `use_launch_agent`
290    /// This setting only works on macOS
291    pub fn set_use_launch_agent(&mut self, use_launch_agent: bool) -> &mut Self {
292        self.use_launch_agent = use_launch_agent;
293        self
294    }
295
296    /// Set the args
297    pub fn set_args(&mut self, args: &[impl AsRef<str>]) -> &mut Self {
298        self.args = Some(args.iter().map(|s| s.as_ref().to_string()).collect());
299        self
300    }
301
302    /// Construct a AutoLaunch instance
303    ///
304    /// ## Errors
305    ///
306    /// - `app_name` is none
307    /// - `app_path` is none
308    ///
309    /// ## Panics
310    ///
311    /// - Unsupported target OS
312    pub fn build(&self) -> Result<AutoLaunch> {
313        let app_name = self.app_name.as_ref().ok_or(Error::AppNameNotSpecified)?;
314        let app_path = self.app_path.as_ref().ok_or(Error::AppPathNotSpecified)?;
315        let args = self.args.clone().unwrap_or_default();
316
317        #[cfg(target_os = "linux")]
318        return Ok(AutoLaunch::new(&app_name, &app_path, &args));
319        #[cfg(target_os = "macos")]
320        return Ok(AutoLaunch::new(
321            &app_name,
322            &app_path,
323            self.use_launch_agent,
324            &args,
325        ));
326        #[cfg(target_os = "windows")]
327        return Ok(AutoLaunch::new(&app_name, &app_path, &args));
328
329        #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
330        return Err(Error::UnsupportedOS);
331    }
332}