mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00

While testing the previous PR, I noticed that if stdout is set to None, the same behaviour is shown as in the following report: https://forums.ankiweb.net/t/cannot-switch-versions/64565 This leads me to wonder whether IsTerminal is behaving differently on that user's system, and the use of an env var may be more reliable.
138 lines
3.8 KiB
Rust
138 lines
3.8 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
#[cfg(all(unix, not(target_os = "macos")))]
|
|
pub mod unix;
|
|
|
|
#[cfg(target_os = "macos")]
|
|
pub mod mac;
|
|
|
|
#[cfg(target_os = "windows")]
|
|
pub mod windows;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use anki_process::CommandExt;
|
|
use anyhow::Context;
|
|
use anyhow::Result;
|
|
|
|
pub fn get_exe_and_resources_dirs() -> Result<(PathBuf, PathBuf)> {
|
|
let exe_dir = std::env::current_exe()
|
|
.context("Failed to get current executable path")?
|
|
.parent()
|
|
.context("Failed to get executable directory")?
|
|
.to_owned();
|
|
|
|
let resources_dir = if cfg!(target_os = "macos") {
|
|
// On macOS, resources are in ../Resources relative to the executable
|
|
exe_dir
|
|
.parent()
|
|
.context("Failed to get parent directory")?
|
|
.join("Resources")
|
|
} else {
|
|
// On other platforms, resources are in the same directory as executable
|
|
exe_dir.clone()
|
|
};
|
|
|
|
Ok((exe_dir, resources_dir))
|
|
}
|
|
|
|
pub fn get_uv_binary_name() -> &'static str {
|
|
if cfg!(target_os = "windows") {
|
|
"uv.exe"
|
|
} else if cfg!(target_os = "macos") {
|
|
"uv"
|
|
} else if cfg!(target_arch = "x86_64") {
|
|
"uv.amd64"
|
|
} else {
|
|
"uv.arm64"
|
|
}
|
|
}
|
|
|
|
pub fn respawn_launcher() -> Result<()> {
|
|
use std::process::Stdio;
|
|
|
|
let mut launcher_cmd = if cfg!(target_os = "macos") {
|
|
// On macOS, we need to launch the .app bundle, not the executable directly
|
|
let current_exe =
|
|
std::env::current_exe().context("Failed to get current executable path")?;
|
|
|
|
// Navigate from Contents/MacOS/launcher to the .app bundle
|
|
let app_bundle = current_exe
|
|
.parent() // MacOS
|
|
.and_then(|p| p.parent()) // Contents
|
|
.and_then(|p| p.parent()) // .app
|
|
.context("Failed to find .app bundle")?;
|
|
|
|
let mut cmd = std::process::Command::new("open");
|
|
cmd.arg(app_bundle);
|
|
cmd
|
|
} else {
|
|
let current_exe =
|
|
std::env::current_exe().context("Failed to get current executable path")?;
|
|
std::process::Command::new(current_exe)
|
|
};
|
|
|
|
launcher_cmd
|
|
.stdin(Stdio::null())
|
|
.stdout(Stdio::null())
|
|
.stderr(Stdio::null());
|
|
|
|
#[cfg(windows)]
|
|
{
|
|
use std::os::windows::process::CommandExt;
|
|
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
|
|
const DETACHED_PROCESS: u32 = 0x00000008;
|
|
launcher_cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS);
|
|
}
|
|
|
|
#[cfg(all(unix, not(target_os = "macos")))]
|
|
{
|
|
use std::os::unix::process::CommandExt;
|
|
launcher_cmd.process_group(0);
|
|
}
|
|
|
|
let child = launcher_cmd.ensure_spawn()?;
|
|
std::mem::forget(child);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn launch_anki_normally(mut cmd: std::process::Command) -> Result<()> {
|
|
#[cfg(windows)]
|
|
{
|
|
crate::platform::windows::prepare_to_launch_normally();
|
|
cmd.ensure_success()?;
|
|
}
|
|
#[cfg(unix)]
|
|
cmd.ensure_exec()?;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub use windows::ensure_terminal_shown;
|
|
|
|
#[cfg(unix)]
|
|
pub fn ensure_terminal_shown() -> Result<()> {
|
|
use std::io::IsTerminal;
|
|
|
|
let want_terminal = std::env::var("ANKI_LAUNCHER_WANT_TERMINAL").is_ok();
|
|
let stdout_is_terminal = IsTerminal::is_terminal(&std::io::stdout());
|
|
if want_terminal || !stdout_is_terminal {
|
|
#[cfg(target_os = "macos")]
|
|
mac::relaunch_in_terminal()?;
|
|
#[cfg(not(target_os = "macos"))]
|
|
unix::relaunch_in_terminal()?;
|
|
}
|
|
|
|
// Set terminal title to "Anki Launcher"
|
|
print!("\x1b]2;Anki Launcher\x07");
|
|
Ok(())
|
|
}
|
|
|
|
pub fn ensure_os_supported() -> Result<()> {
|
|
#[cfg(all(unix, not(target_os = "macos")))]
|
|
unix::ensure_glibc_supported()?;
|
|
|
|
Ok(())
|
|
}
|