diff --git a/crates/fig_os_shim/src/fs.rs b/crates/fig_os_shim/src/fs.rs index 95d3783b15..8500d0216b 100644 --- a/crates/fig_os_shim/src/fs.rs +++ b/crates/fig_os_shim/src/fs.rs @@ -551,7 +551,7 @@ fn append(a: impl AsRef, b: impl AsRef) -> PathBuf { // If b has a drive letter and it's different from a's drive letter (if any), // we need to handle it specially - let result_path = if let Some(b_drive) = b_drive { + if let Some(b_drive) = b_drive { if a_str.starts_with(b_drive) { // Same drive, continue with normal processing let path_str = b_without_drive; @@ -600,9 +600,7 @@ fn append(a: impl AsRef, b: impl AsRef) -> PathBuf { } a_path.join(b_normalized) - }; - - result_path + } } #[cfg(test)] diff --git a/crates/fig_proto/build.rs b/crates/fig_proto/build.rs index 9cca6f64e9..b270659896 100644 --- a/crates/fig_proto/build.rs +++ b/crates/fig_proto/build.rs @@ -31,9 +31,17 @@ fn protoc_version() -> Option { fn download_protoc() { let protoc_version = "26.1"; - let tmp_folder = tempfile::tempdir().unwrap(); + #[cfg(not(windows))] + download_protoc_unix(protoc_version, &tmp_folder); + + #[cfg(windows)] + download_protoc_windows(protoc_version, &tmp_folder); +} + +#[cfg(not(windows))] +fn download_protoc_unix(protoc_version: &str, tmp_folder: &tempfile::TempDir) { let os = match std::env::consts::OS { "linux" => "linux", "macos" => "osx", @@ -88,6 +96,80 @@ fn download_protoc() { std::env::set_var("PROTOC", out_bin); } +#[cfg(windows)] +fn download_protoc_windows(protoc_version: &str, tmp_folder: &tempfile::TempDir) { + // Determine Windows architecture (win32 or win64) + let win_arch = match std::env::consts::ARCH { + "x86_64" => "win64", + "x86" => "win32", + arch => panic!("Unsupported Windows architecture: {arch}"), + }; + + // Windows-specific checksums + let checksum = match win_arch { + "win64" => "9090d135a1159042b13b4e51b210e40cb820d85a5032a6eca5f9b3ca3bdfb539", + "win32" => "11fc8f280922e86d917e30f7b9960a1e77453f64990d965080697b394a8d9d74", + _ => unreachable!(), + }; + + // Windows-specific URL format + let download_url = format!( + "https://github.com/protocolbuffers/protobuf/releases/download/v{protoc_version}/protoc-{protoc_version}-{win_arch}.zip" + ); + + eprintln!("Downloading protoc from: {download_url}"); + + // Download using curl (assuming curl is available on Windows) + let mut download_command = Command::new("curl"); + download_command + .arg("-Lf") + .arg(download_url) + .arg("-o") + .arg(tmp_folder.path().join("protoc.zip")); + assert!(download_command.spawn().unwrap().wait().unwrap().success()); + + // Verify checksum using PowerShell + let mut checksum_command = Command::new("powershell"); + checksum_command.arg("-Command").arg(format!( + "(Get-FileHash -Path '{}' -Algorithm SHA256).Hash.ToLower()", + tmp_folder.path().join("protoc.zip").display() + )); + let checksum_output = checksum_command.output().unwrap(); + let checksum_output = String::from_utf8(checksum_output.stdout).unwrap().trim().to_lowercase(); + + eprintln!("checksum: {checksum_output:?}"); + assert_eq!( + checksum_output, + checksum.to_lowercase(), + "Checksum verification failed. Expected: {}, Got: {}", + checksum.to_lowercase(), + checksum_output + ); + + // Extract using PowerShell + let mut unzip_command = Command::new("powershell"); + unzip_command.arg("-Command").arg(format!( + "Expand-Archive -Path '{}' -DestinationPath '{}' -Force", + tmp_folder.path().join("protoc.zip").display(), + tmp_folder.path().display() + )); + assert!(unzip_command.spawn().unwrap().wait().unwrap().success()); + + // Set output path with .exe extension for Windows + let out_bin = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("protoc.exe"); + + // Copy the protoc binary using PowerShell + let mut copy_command = Command::new("powershell"); + copy_command.arg("-Command").arg(format!( + "Copy-Item -Path '{}' -Destination '{}'", + tmp_folder.path().join("bin").join("protoc.exe").display(), + out_bin.display() + )); + assert!(copy_command.spawn().unwrap().wait().unwrap().success()); + + std::env::set_var("PROTOC", out_bin); +} + fn main() -> Result<()> { println!("cargo:rerun-if-changed=build.rs"); diff --git a/crates/fig_util/Cargo.toml b/crates/fig_util/Cargo.toml index b9969daae3..2406e38dcd 100644 --- a/crates/fig_util/Cargo.toml +++ b/crates/fig_util/Cargo.toml @@ -52,6 +52,7 @@ windows = { version = "0.58.0", features = [ "Win32_System_Kernel", "Win32_System_ProcessStatus", "Win32_System_Threading", + "Wdk_System_Threading", ] } winreg = "0.55.0" diff --git a/crates/fig_util/src/directories.rs b/crates/fig_util/src/directories.rs index af6605671e..20fdb8d05b 100644 --- a/crates/fig_util/src/directories.rs +++ b/crates/fig_util/src/directories.rs @@ -14,6 +14,9 @@ use fig_os_shim::{ use thiserror::Error; use time::OffsetDateTime; +#[cfg(unix)] +use crate::RUNTIME_DIR_NAME; +use crate::TAURI_PRODUCT_NAME; use crate::env_var::{ Q_BUNDLE_METADATA_PATH, Q_PARENT, @@ -23,10 +26,6 @@ use crate::system_info::{ in_cloudshell, is_remote, }; -use crate::{ - RUNTIME_DIR_NAME, - TAURI_PRODUCT_NAME, -}; macro_rules! utf8_dir { ($name:ident, $($arg:ident: $type:ty),*) => { @@ -130,21 +129,16 @@ pub fn config_dir() -> Result { /// This should be removed at some point in the future, once all our users have migrated /// - MacOS: `$HOME/Library/Application Support/codewhisperer` pub fn old_fig_data_dir() -> Result { - cfg_if::cfg_if! { - if #[cfg(unix)] { - Ok(dirs::data_local_dir() - .ok_or(DirectoryError::NoHomeDirectory)? - .join("codewhisperer")) - } else if #[cfg(windows)] { - Ok(fig_dir()?.join("userdata")) - } - } + Ok(dirs::data_local_dir() + .ok_or(DirectoryError::NoHomeDirectory)? + .join("codewhisperer")) } /// The q data directory /// /// - Linux: `$XDG_DATA_HOME/amazon-q` or `$HOME/.local/share/amazon-q` /// - MacOS: `$HOME/Library/Application Support/amazon-q` +/// - Windows: `%LOCALAPPDATA%\AmazonQ` pub fn fig_data_dir() -> Result { cfg_if::cfg_if! { if #[cfg(unix)] { @@ -152,7 +146,9 @@ pub fn fig_data_dir() -> Result { .ok_or(DirectoryError::NoHomeDirectory)? .join("amazon-q")) } else if #[cfg(windows)] { - Ok(fig_dir()?.join("userdata")) + Ok(dirs::data_local_dir() + .ok_or(DirectoryError::NoHomeDirectory)? + .join("AmazonQ")) } } } @@ -165,6 +161,7 @@ pub fn fig_data_dir_ctx(fs: &impl FsProvider) -> Result { /// /// - Linux: `$XDG_DATA_HOME` or `$HOME/.local/share` /// - MacOS: `$HOME/Library/Application Support` +/// - Windows: `%LOCALAPPDATA%` pub fn local_data_dir(ctx: &Ctx) -> Result { let env = ctx.env(); match ctx.platform().os() { @@ -175,6 +172,12 @@ pub fn local_data_dir(ctx: &Ct Ok(home_dir_ctx(ctx)?.join(".local/share")) }, Os::Mac => Ok(home_dir_ctx(ctx)?.join("Library/Application Support")), + Os::Windows => { + if let Some(path) = env.get_os("LOCALAPPDATA") { + return Ok(path.into()); + } + Ok(home_dir_ctx(ctx)?.join("AppData").join("Local")) + }, os => Err(DirectoryError::UnsupportedOs(os)), } } @@ -183,6 +186,7 @@ pub fn local_data_dir(ctx: &Ct /// /// - Linux: `$XDG_CACHE_HOME/amazon-q` or `$HOME/.cache/amazon-q` /// - MacOS: `$HOME/Library/Caches/amazon-q` +/// - Windows: `%LOCALAPPDATA%\AmazonQ\cache` pub fn cache_dir() -> Result { cfg_if::cfg_if! { if #[cfg(unix)] { @@ -190,7 +194,9 @@ pub fn cache_dir() -> Result { .ok_or(DirectoryError::NoHomeDirectory)? .join("amazon-q")) } else if #[cfg(windows)] { - Ok(fig_dir()?.join("cache")) + Ok(dirs::cache_dir() + .ok_or(DirectoryError::NoHomeDirectory)? + .join("AmazonQ")) } } } @@ -213,33 +219,40 @@ fn macos_tempdir() -> Result { /// /// The XDG_RUNTIME_DIR is set by systemd , /// if this is not set such as on macOS it will fallback to TMPDIR which is secure on macOS -#[cfg(unix)] +/// On Windows, it uses the TEMP directory pub fn runtime_dir() -> Result { - let mut dir = dirs::runtime_dir(); - dir = dir.or_else(|| std::env::var_os("TMPDIR").map(PathBuf::from)); - cfg_if::cfg_if! { - if #[cfg(target_os = "macos")] { - let macos_tempdir = macos_tempdir()?; - dir = dir.or(Some(macos_tempdir)); - } else { - dir = dir.or_else(|| Some(std::env::temp_dir())); + if #[cfg(unix)] { + let mut dir = dirs::runtime_dir(); + dir = dir.or_else(|| std::env::var_os("TMPDIR").map(PathBuf::from)); + + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let macos_tempdir = macos_tempdir()?; + dir = dir.or(Some(macos_tempdir)); + } else { + dir = dir.or_else(|| Some(std::env::temp_dir())); + } + } + + dir.ok_or(DirectoryError::NoRuntimeDirectory) + } else if #[cfg(windows)] { + Ok(std::env::temp_dir()) } } - - dir.ok_or(DirectoryError::NoRuntimeDirectory) } /// The q sockets directory of the local q installation /// /// - Linux: $XDG_RUNTIME_DIR/cwrun /// - MacOS: $TMPDIR/cwrun +/// - Windows: %TEMP%\sockets pub fn sockets_dir() -> Result { cfg_if::cfg_if! { if #[cfg(unix)] { Ok(runtime_dir()?.join(RUNTIME_DIR_NAME)) } else if #[cfg(windows)] { - Ok(fig_dir()?.join("sockets")) + Ok(runtime_dir()?.join("AmazonQ").join("sockets")) } } } @@ -251,6 +264,7 @@ pub fn sockets_dir() -> Result { /// /// - Linux: $XDG_RUNTIME_DIR/cwrun /// - MacOS: $TMPDIR/cwrun +/// - Windows: %TEMP%\sockets pub fn host_sockets_dir() -> Result { // TODO: make this work again // #[cfg(target_os = "linux")] @@ -289,27 +303,24 @@ pub fn autocomplete_specs_dir() -> Result { /// The directory to all the fig logs /// - Linux: `/tmp/fig/$USER/logs` /// - MacOS: `$TMPDIR/logs` -/// - Windows: `%TEMP%\fig\logs` +/// - Windows: `%TEMP%\AmazonQ\logs` pub fn logs_dir() -> Result { cfg_if::cfg_if! { if #[cfg(unix)] { use crate::CLI_BINARY_NAME; Ok(runtime_dir()?.join(format!("{CLI_BINARY_NAME}log"))) } else if #[cfg(windows)] { - Ok(std::env::temp_dir().join("amazon-q").join("logs")) + Ok(std::env::temp_dir().join("AmazonQ").join("logs")) } } } /// The directory where fig places all data-sensitive backups +/// +/// - Linux/MacOS: `$HOME/.amazon-q.dotfiles.bak` +/// - Windows: `%USERPROFILE%\.amazon-q.dotfiles.bak` pub fn backups_dir() -> Result { - cfg_if::cfg_if! { - if #[cfg(unix)] { - Ok(home_dir()?.join(".amazon-q.dotfiles.bak")) - } else if #[cfg(windows)] { - Ok(fig_data_dir()?.join("backups")) - } - } + Ok(home_dir()?.join(".amazon-q.dotfiles.bak")) } /// The directory for time based data-sensitive backups @@ -340,7 +351,7 @@ pub fn chat_profiles_dir(ctx: &Ctx) -> Result Result { Ok(host_sockets_dir()?.join("desktop.sock")) } @@ -350,8 +361,9 @@ pub fn desktop_socket_path() -> Result { // - Linux/MacOS not on ssh: /// - MacOS: `$TMPDIR/cwrun/remote.sock` /// - Linux: `$XDG_RUNTIME_DIR/cwrun/remote.sock` -/// - Windows: `%APPDATA%/Fig/%USER%/remote.sock` +/// - Windows: `%TEMP%\sockets\remote.sock` pub fn remote_socket_path() -> Result { + // Normal implementation for non-test code // TODO(grant): This is only enabled on Linux for now to prevent public dist if is_remote() && !in_cloudshell() && cfg!(target_os = "linux") { if let Some(parent_socket) = std::env::var_os(Q_PARENT) { @@ -368,7 +380,7 @@ pub fn remote_socket_path() -> Result { /// /// - MacOS: `$TMPDIR/cwrun/remote.sock` /// - Linux: `$XDG_RUNTIME_DIR/cwrun/remote.sock` -/// - Windows: `%APPDATA%/Fig/%USER%/remote.sock` +/// - Windows: `%TEMP%\sockets\remote.sock` pub fn local_remote_socket_path() -> Result { Ok(host_sockets_dir()?.join("remote.sock")) } @@ -378,7 +390,7 @@ pub fn local_remote_socket_path() -> Result { /// - Linux/Macos: `/var/tmp/fig/%USERNAME%/figterm/$SESSION_ID.sock` /// - MacOS: `$TMPDIR/cwrun/t/$SESSION_ID.sock` /// - Linux: `$XDG_RUNTIME_DIR/cwrun/t/$SESSION_ID.sock` -/// - Windows: `%APPDATA%\Fig\$SESSION_ID.sock` +/// - Windows: `%TEMP%\sockets\t\$SESSION_ID.sock` pub fn figterm_socket_path(session_id: impl Display) -> Result { Ok(sockets_dir()?.join("t").join(format!("{session_id}.sock"))) } @@ -387,12 +399,15 @@ pub fn figterm_socket_path(session_id: impl Display) -> Result { /// /// - MacOS: "/Applications/Amazon Q.app/Contents/Resources" /// - Linux: "/usr/share/fig" +/// - Windows: "%LOCALAPPDATA%\AmazonQ\resources" pub fn resources_path() -> Result { cfg_if::cfg_if! { if #[cfg(all(unix, not(target_os = "macos")))] { Ok(std::path::Path::new("/usr/share/fig").into()) } else if #[cfg(target_os = "macos")] { Ok(crate::app_bundle_path().join(crate::macos::BUNDLE_CONTENTS_RESOURCE_PATH)) + } else if #[cfg(windows)] { + Ok(fig_data_dir()?.join("resources")) } } } @@ -411,6 +426,7 @@ pub fn resources_path_ctx(ctx: &Ctx) -> Res Ok(format!("/usr/share/{}", PACKAGE_NAME).into()) } }, + fig_os_shim::Os::Windows => Ok(fig_data_dir()?.join("resources")), _ => Err(DirectoryError::UnsupportedOs(os)), } } @@ -419,12 +435,13 @@ pub fn resources_path_ctx(ctx: &Ctx) -> Res /// /// - MacOS: "/Applications/Amazon Q.app/Contents/Resources/manifest.json" /// - Linux: "/usr/share/fig/manifest.json" +/// - Windows: "%LOCALAPPDATA%\AmazonQ\resources\bin\manifest.json" pub fn manifest_path() -> Result { cfg_if::cfg_if! { if #[cfg(unix)] { Ok(resources_path()?.join("manifest.json")) } else if #[cfg(target_os = "windows")] { - Ok(managed_binaries_dir()?.join("manifest.json")) + Ok(resources_path()?.join("bin").join("manifest.json")) } } } @@ -442,11 +459,19 @@ pub fn bundle_metadata_path(ctx: &Ctx) -> R } /// The path to the fig settings file +/// +/// - Linux: `$HOME/.local/share/amazon-q/settings.json` +/// - MacOS: `$HOME/Library/Application Support/amazon-q/settings.json` +/// - Windows: `%LOCALAPPDATA%\AmazonQ\settings.json` pub fn settings_path() -> Result { Ok(fig_data_dir()?.join("settings.json")) } /// The path to the lock file used to indicate that the app is updating +/// +/// - Linux: `$HOME/.local/share/amazon-q/update.lock` +/// - MacOS: `$HOME/Library/Application Support/amazon-q/update.lock` +/// - Windows: `%LOCALAPPDATA%\AmazonQ\update.lock` pub fn update_lock_path(ctx: &impl FsProvider) -> Result { Ok(fig_data_dir_ctx(ctx)?.join("update.lock")) } @@ -540,12 +565,14 @@ mod linux_tests { fn all_paths() { let ctx = Context::new(); assert!(home_dir().is_ok()); + #[cfg(unix)] assert!(home_local_bin().is_ok()); assert!(fig_data_dir().is_ok()); assert!(sockets_dir().is_ok()); assert!(remote_socket_path().is_ok()); assert!(local_remote_socket_path().is_ok()); assert!(figterm_socket_path("test").is_ok()); + assert!(resources_path().is_ok()); assert!(manifest_path().is_ok()); assert!(backups_dir().is_ok()); assert!(logs_dir().is_ok()); @@ -568,10 +595,25 @@ mod tests { /// own otherwise we will set permissions of directories we shouldn't #[test] fn test_socket_paths() { + #[cfg(unix)] assert_eq!( host_sockets_dir().unwrap().file_name().unwrap().to_str().unwrap(), format!("cwrun") ); + + #[cfg(windows)] + assert_eq!( + host_sockets_dir().unwrap().file_name().unwrap().to_str().unwrap(), + format!("sockets") + ); + + #[cfg(unix)] + assert_eq!( + figterm_socket_path("").unwrap().parent().unwrap().file_name().unwrap(), + "t" + ); + + #[cfg(windows)] assert_eq!( figterm_socket_path("").unwrap().parent().unwrap().file_name().unwrap(), "t" @@ -649,7 +691,9 @@ mod tests { #[cfg(unix)] #[test] fn snapshot_home_local_bin() { + #[cfg(target_os = "linux")] linux!(home_local_bin(), @"$HOME/.local/bin"); + #[cfg(target_os = "macos")] macos!(home_local_bin(), @"$HOME/.local/bin"); } @@ -657,63 +701,63 @@ mod tests { fn snapshot_fig_data_dir() { linux!(fig_data_dir(), @"$HOME/.local/share/amazon-q"); macos!(fig_data_dir(), @"$HOME/Library/Application Support/amazon-q"); - windows!(fig_data_dir(), @r"C:\Users\$USER\AppData\Local\Fig\userdata"); + windows!(fig_data_dir(), @r"C:\Users\$USER\AppData\Local\AmazonQ"); } #[test] fn snapshot_sockets_dir() { linux!(sockets_dir(), @"$XDG_RUNTIME_DIR/cwrun"); macos!(sockets_dir(), @"$TMPDIR/cwrun"); - windows!(sockets_dir(), @r"C:\Users\$USER\AppData\Local\Fig\sockets"); + windows!(sockets_dir(), @r"C:\Users\$USER\AppData\Local\Temp\AmazonQ\sockets"); } #[test] fn snapshot_themes_dir() { linux!(themes_dir(&Context::new()), @"/usr/share/fig/themes"); macos!(themes_dir(&Context::new()), @"/Applications/Amazon Q.app/Contents/Resources/themes"); - windows!(themes_dir(&Context::new()), @r"C:\Users\$USER\AppData\Local\Fig\userdata\themes\themes"); + windows!(themes_dir(&Context::new()), @r"C:\Users\$USER\AppData\Local\AmazonQ\resources\themes"); } #[test] fn snapshot_backups_dir() { linux!(backups_dir(), @"$HOME/.amazon-q.dotfiles.bak"); macos!(backups_dir(), @"$HOME/.amazon-q.dotfiles.bak"); - windows!(backups_dir(), @r"C:\Users\$USER\AppData\Local\Fig\userdata\backups"); + windows!(backups_dir(), @r"C:\Users\$USER\.amazon-q.dotfiles.bak"); } #[test] fn snapshot_fig_socket_path() { linux!(desktop_socket_path(), @"$XDG_RUNTIME_DIR/cwrun/desktop.sock"); macos!(desktop_socket_path(), @"$TMPDIR/cwrun/desktop.sock"); - windows!(desktop_socket_path(), @r"C:\Users\$USER\AppData\Local\Fig\sockets\desktop.sock"); + windows!(desktop_socket_path(), @r"C:\Users\$USER\AppData\Local\Temp\AmazonQ\sockets\desktop.sock"); } #[test] fn snapshot_remote_socket_path() { linux!(remote_socket_path(), @"$XDG_RUNTIME_DIR/cwrun/remote.sock"); macos!(remote_socket_path(), @"$TMPDIR/cwrun/remote.sock"); - windows!(remote_socket_path(), @r"C:\Users\$USER\AppData\Local\Fig\sockets\remote.sock"); + windows!(remote_socket_path(), @r"C:\Users\$USER\AppData\Local\Temp\AmazonQ\sockets\remote.sock"); } #[test] fn snapshot_local_remote_socket_path() { linux!(local_remote_socket_path(), @"$XDG_RUNTIME_DIR/cwrun/remote.sock"); macos!(local_remote_socket_path(), @"$TMPDIR/cwrun/remote.sock"); - windows!(local_remote_socket_path(), @r"C:\Users\$USER\AppData\Local\Fig\sockets\remote.sock"); + windows!(local_remote_socket_path(), @r"C:\Users\$USER\AppData\Local\Temp\AmazonQ\sockets\remote.sock"); } #[test] fn snapshot_figterm_socket_path() { linux!(figterm_socket_path("$SESSION_ID"), @"$XDG_RUNTIME_DIR/cwrun/t/$SESSION_ID.sock"); macos!(figterm_socket_path("$SESSION_ID"), @"$TMPDIR/cwrun/t/$SESSION_ID.sock"); - windows!(figterm_socket_path("$SESSION_ID"), @r"C:\Users\$USER\AppData\Local\Fig\sockets\figterm\$SESSION_ID.sock"); + windows!(figterm_socket_path("$SESSION_ID"), @r"C:\Users\$USER\AppData\Local\Temp\AmazonQ\sockets\t\$SESSION_ID.sock"); } #[test] fn snapshot_settings_path() { linux!(settings_path(), @"$HOME/.local/share/amazon-q/settings.json"); macos!(settings_path(), @"$HOME/Library/Application Support/amazon-q/settings.json"); - windows!(settings_path(), @r"C:\Users\$USER\AppData\Lcoal\Fig\settings.json"); + windows!(settings_path(), @r"C:\Users\$USER\AppData\Local\AmazonQ\settings.json"); } #[test] @@ -721,7 +765,7 @@ mod tests { let ctx = Context::new(); linux!(update_lock_path(&ctx), @"$HOME/.local/share/amazon-q/update.lock"); macos!(update_lock_path(&ctx), @"$HOME/Library/Application Support/amazon-q/update.lock"); - windows!(update_lock_path(&ctx), @r"C:\Users\$USER\AppData\Local\Fig\userdata\update.lock"); + windows!(update_lock_path(&ctx), @r"C:\Users\$USER\AppData\Local\AmazonQ\update.lock"); } #[test] diff --git a/crates/fig_util/src/manifest.rs b/crates/fig_util/src/manifest.rs index 01e311fdac..b560c6d560 100644 --- a/crates/fig_util/src/manifest.rs +++ b/crates/fig_util/src/manifest.rs @@ -66,6 +66,15 @@ pub enum TargetTriple { #[serde(rename = "aarch64-unknown-linux-musl")] #[strum(serialize = "aarch64-unknown-linux-musl")] AArch64UnknownLinuxMusl, + #[serde(rename = "x86_64-pc-windows-msvc")] + #[strum(serialize = "x86_64-pc-windows-msvc")] + X86_64PcWindowsMsvc, + #[serde(rename = "i686-pc-windows-msvc")] + #[strum(serialize = "i686-pc-windows-msvc")] + I686PcWindowsMsvc, + #[serde(rename = "aarch64-pc-windows-msvc")] + #[strum(serialize = "aarch64-pc-windows-msvc")] + AArch64PcWindowsMsvc, #[strum(default)] Other(String), } @@ -83,6 +92,12 @@ impl TargetTriple { TargetTriple::X86_64UnknownLinuxMusl } else if #[cfg(all(target_os = "linux", target_env = "musl", target_arch = "aarch64"))] { TargetTriple::AArch64UnknownLinuxMusl + } else if #[cfg(all(target_os = "windows", target_arch = "x86_64"))] { + TargetTriple::X86_64PcWindowsMsvc + } else if #[cfg(all(target_os = "windows", target_arch = "x86"))] { + TargetTriple::I686PcWindowsMsvc + } else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] { + TargetTriple::AArch64PcWindowsMsvc } else { compile_error!("unknown target") } @@ -108,6 +123,7 @@ pub enum Variant { pub enum Os { Macos, Linux, + Windows, #[strum(default)] Other(String), } @@ -117,6 +133,7 @@ impl Os { match std::env::consts::OS { "macos" => Os::Macos, "linux" => Os::Linux, + "windows" => Os::Windows, _ => panic!("Unsupported OS: {}", std::env::consts::OS), } } diff --git a/crates/fig_util/src/process_info/mod.rs b/crates/fig_util/src/process_info/mod.rs index cc415a785c..d939f013dc 100644 --- a/crates/fig_util/src/process_info/mod.rs +++ b/crates/fig_util/src/process_info/mod.rs @@ -18,8 +18,6 @@ mod macos; #[cfg(target_os = "windows")] mod windows; -#[cfg(target_os = "windows")] -pub use self::windows::*; #[cfg(target_os = "freebsd")] mod freebsd; diff --git a/crates/fig_util/src/process_info/windows.rs b/crates/fig_util/src/process_info/windows.rs index 5ecfa6615e..01814cf090 100644 --- a/crates/fig_util/src/process_info/windows.rs +++ b/crates/fig_util/src/process_info/windows.rs @@ -6,6 +6,10 @@ use std::mem::{ use std::ops::Deref; use std::path::PathBuf; +use windows::Wdk::System::Threading::{ + NtQueryInformationProcess, + ProcessBasicInformation, +}; use windows::Win32::Foundation::{ CloseHandle, HANDLE, @@ -13,14 +17,12 @@ use windows::Win32::Foundation::{ }; use windows::Win32::System::Threading::{ GetCurrentProcessId, - NtQueryInformationProcess, OpenProcess, PROCESS_BASIC_INFORMATION, PROCESS_NAME_FORMAT, PROCESS_QUERY_INFORMATION, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ, - ProcessBasicInformation, QueryFullProcessImageNameA, }; use windows::core::PSTR; @@ -41,7 +43,7 @@ impl SafeHandle { impl Drop for SafeHandle { fn drop(&mut self) { unsafe { - CloseHandle(self.0); + let _ = CloseHandle(self.0); } } } @@ -86,7 +88,7 @@ impl PidExt for Pid { if NtQueryInformationProcess( *handle, ProcessBasicInformation, - info.as_mut_ptr() as *mut _, + info.as_mut_ptr().cast(), size_of::() as _, &mut len, ) @@ -97,7 +99,7 @@ impl PidExt for Pid { let info = info.assume_init(); - if info.InheritedFromUniqueProcessId as usize != 0 { + if info.InheritedFromUniqueProcessId != 0 { Some(Pid(info.InheritedFromUniqueProcessId as u32)) } else { None @@ -114,13 +116,13 @@ impl PidExt for Pid { let mut process_name = [0; MAX_PATH as usize + 1]; process_name[MAX_PATH as usize] = u8::try_from('\0').unwrap(); - if !QueryFullProcessImageNameA( + if QueryFullProcessImageNameA( handle, PROCESS_NAME_FORMAT(0), PSTR(process_name.as_mut_ptr()), &mut len, ) - .as_bool() + .is_err() { return None; } diff --git a/crates/fig_util/src/shell.rs b/crates/fig_util/src/shell.rs index 835e174fc3..9414505b32 100644 --- a/crates/fig_util/src/shell.rs +++ b/crates/fig_util/src/shell.rs @@ -189,6 +189,7 @@ mod tests { use super::*; use crate::build::SKIP_FISH_TESTS; + #[cfg(not(windows))] #[tokio::test] async fn test_shell_version() { let tests = [