feat: add cross-platform support via platform detection module
Introduces src/platform.rs with OS detection and env var overrides. All hardcoded Linux paths replaced with Platform::detect() across 8 source files. Key changes: - New Platform struct with 11 fields (all overridable via env vars) - /proc/ access gated to Linux (#[cfg(target_os = "linux")]) - pgrep/pkill patterns broadened for cross-platform LS discovery - sec-ch-ua-platform header now dynamic per OS - Token, traces, config, CA cert paths use platform module - LD_PRELOAD DNS redirect gated to Linux only - Setup scripts for Linux (systemd) and macOS (launchd) - find_ls_binary_path has cross-platform stubs All 46 tests pass, cargo check clean.
This commit is contained in:
@@ -21,26 +21,54 @@ struct DetectedVersions {
|
||||
/// back to its binary, then walking up to the app root. Falls back to
|
||||
/// well-known install paths.
|
||||
fn find_install_dir() -> Option<String> {
|
||||
// 1. Try tracing the running language server → /usr/share/antigravity/resources/app/extensions/...
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.args(["-c", "pgrep -f language_server_linux | head -1"])
|
||||
.output()
|
||||
let p = crate::platform::Platform::detect();
|
||||
|
||||
// 1. Check if platform-detected app_root exists
|
||||
let app_root_parent = std::path::Path::new(&p.app_root)
|
||||
.parent()
|
||||
.and_then(|p| p.parent())
|
||||
.map(|p| p.to_string_lossy().to_string());
|
||||
if let Some(ref dir) = app_root_parent {
|
||||
if fs::metadata(format!("{dir}/resources/app/product.json")).is_ok() {
|
||||
return Some(dir.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try tracing the running language server via /proc (Linux only)
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let pid = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if !pid.is_empty() {
|
||||
if let Ok(exe) = fs::read_link(format!("/proc/{pid}/exe")) {
|
||||
let exe_str = exe.to_string_lossy().to_string();
|
||||
// exe is like: /usr/share/antigravity/resources/app/extensions/antigravity/bin/language_server_linux_x64
|
||||
// We want: /usr/share/antigravity
|
||||
if let Some(idx) = exe_str.find("/resources/") {
|
||||
return Some(exe_str[..idx].to_string());
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.args(["-c", "pgrep -f language_server | head -1"])
|
||||
.output()
|
||||
{
|
||||
let pid = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if !pid.is_empty() {
|
||||
if let Ok(exe) = fs::read_link(format!("/proc/{pid}/exe")) {
|
||||
let exe_str = exe.to_string_lossy().to_string();
|
||||
if let Some(idx) = exe_str.find("/resources/") {
|
||||
return Some(exe_str[..idx].to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fall back to well-known install paths
|
||||
for path in &["/usr/share/antigravity", "/opt/Antigravity"] {
|
||||
// 3. Fall back to well-known install paths
|
||||
#[cfg(target_os = "linux")]
|
||||
let candidates = ["/usr/share/antigravity", "/opt/Antigravity"];
|
||||
#[cfg(target_os = "macos")]
|
||||
let candidates = [
|
||||
"/Applications/Antigravity.app/Contents",
|
||||
&format!("{}/Applications/Antigravity.app/Contents", std::env::var("HOME").unwrap_or_default()),
|
||||
];
|
||||
#[cfg(target_os = "windows")]
|
||||
let candidates = [
|
||||
&format!("{}\\Programs\\Antigravity", std::env::var("LOCALAPPDATA").unwrap_or_default()),
|
||||
];
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
||||
let candidates: [&str; 0] = [];
|
||||
|
||||
for path in &candidates {
|
||||
if fs::metadata(format!("{path}/resources/app/product.json")).is_ok() {
|
||||
return Some(path.to_string());
|
||||
}
|
||||
@@ -178,14 +206,23 @@ pub const LS_SERVICE: &str = "exa.language_server_pb.LanguageServerService";
|
||||
|
||||
/// Log base directory for Antigravity.
|
||||
pub fn log_base() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
|
||||
format!("{home}/.config/Antigravity/logs")
|
||||
let p = crate::platform::Platform::detect();
|
||||
// Antigravity logs live next to its state DB
|
||||
let state_parent = std::path::Path::new(&p.state_db_path)
|
||||
.parent()
|
||||
.and_then(|p| p.parent())
|
||||
.and_then(|p| p.parent())
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
|
||||
format!("{home}/.config/Antigravity")
|
||||
});
|
||||
format!("{state_parent}/logs")
|
||||
}
|
||||
|
||||
/// Token file path.
|
||||
pub fn token_file_path() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
|
||||
format!("{home}/.config/zerogravity/token")
|
||||
crate::platform::Platform::detect().token_path.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
/// User-Agent string matching the Electron webview — computed once.
|
||||
|
||||
Reference in New Issue
Block a user