From 8a2fcb9f3ec29967a093f6b17b2fbd888fcf62c0 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Mon, 3 Mar 2025 12:08:16 +0100 Subject: [PATCH 01/12] [rust] Replace WMIC commands (to be deprecated) by PowerShell in Windows --- rust/src/config.rs | 2 +- rust/src/files.rs | 4 ++-- rust/src/lib.rs | 15 +++++++++------ rust/src/shell.rs | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/rust/src/config.rs b/rust/src/config.rs index b92b3fac2fe89..b4feaa9ca3a83 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -21,7 +21,7 @@ use crate::{ default_cache_folder, format_one_arg, path_to_string, Command, ENV_PROCESSOR_ARCHITECTURE, REQUEST_TIMEOUT_SEC, UNAME_COMMAND, }; -use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, TTL_SEC, WMIC_COMMAND_OS}; +use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, PS_GET_OS_COMMAND, TTL_SEC}; use anyhow::anyhow; use anyhow::Error; use std::cell::RefCell; diff --git a/rust/src/files.rs b/rust/src/files.rs index 8dc208a3cfb85..53753b93cb04f 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -19,7 +19,7 @@ use crate::config::OS; use crate::config::OS::WINDOWS; use crate::{ format_one_arg, format_three_args, run_shell_command_by_os, Command, Logger, CP_VOLUME_COMMAND, - HDIUTIL_ATTACH_COMMAND, HDIUTIL_DETACH_COMMAND, MACOS, MSIEXEC_INSTALL_COMMAND, + HDIUTIL_ATTACH_COMMAND, HDIUTIL_DETACH_COMMAND, MACOS, PS_MSIEXEC_INSTALL_COMMAND, }; use anyhow::anyhow; use anyhow::Error; @@ -309,7 +309,7 @@ pub fn install_msi(msi_file: &str, log: &Logger, os: &str) -> Result<(), Error> msi_file_name.to_str().unwrap_or_default() )); - let command = Command::new_single(format_one_arg(MSIEXEC_INSTALL_COMMAND, msi_file)); + let command = Command::new_single(format_one_arg(PS_MSIEXEC_INSTALL_COMMAND, msi_file)); log.trace(format!("Running command: {}", command.display())); run_shell_command_by_os(os, command)?; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 851ba31dd1da2..9a1afb1ddeb14 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -75,8 +75,10 @@ pub const DEV: &str = "dev"; pub const CANARY: &str = "canary"; pub const NIGHTLY: &str = "nightly"; pub const ESR: &str = "esr"; -pub const WMIC_COMMAND: &str = "wmic datafile where name='{}' get Version /value"; -pub const WMIC_COMMAND_OS: &str = "wmic os get osarchitecture"; +pub const PS_GET_VERSION_COMMAND: &str = r#"(Get-Item "{}").VersionInfo.ProductVersion"#; +pub const PS_GET_OS_COMMAND: &str = "(Get-WmiObject Win32_OperatingSystem).OSArchitecture"; +pub const PS_MSIEXEC_INSTALL_COMMAND: &str = + r#"Start-Process -FilePath msiexec -ArgumentList "/i {} /qn ALLOWDOWNGRADE=1" -Wait"#; pub const REG_VERSION_ARG: &str = "version"; pub const REG_CURRENT_VERSION_ARG: &str = "CurrentVersion"; pub const REG_PV_ARG: &str = "pv"; @@ -85,7 +87,6 @@ pub const PLIST_COMMAND: &str = pub const HDIUTIL_ATTACH_COMMAND: &str = "hdiutil attach {}"; pub const HDIUTIL_DETACH_COMMAND: &str = "hdiutil detach /Volumes/{}"; pub const CP_VOLUME_COMMAND: &str = "cp -R /Volumes/{}/{}.app {}"; -pub const MSIEXEC_INSTALL_COMMAND: &str = "start /wait msiexec /i {} /qn ALLOWDOWNGRADE=1"; pub const WINDOWS_CHECK_ADMIN_COMMAND: &str = "net session"; pub const DASH_VERSION: &str = "{}{}{} -v"; pub const DASH_DASH_VERSION: &str = "{}{}{} --version"; @@ -1158,9 +1159,11 @@ pub trait SeleniumManager { let mut commands = Vec::new(); if WINDOWS.is(self.get_os()) { if !escaped_browser_path.is_empty() { - let wmic_command = - Command::new_single(format_one_arg(WMIC_COMMAND, &escaped_browser_path)); - commands.push(wmic_command); + let get_version_command = Command::new_single(format_one_arg( + PS_GET_VERSION_COMMAND, + &escaped_browser_path, + )); + commands.push(get_version_command); } if !self.is_browser_version_unstable() { let reg_command = diff --git a/rust/src/shell.rs b/rust/src/shell.rs index 203ba693a8924..9696eb509f59f 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -77,7 +77,7 @@ pub fn run_shell_command_with_log( pub fn run_shell_command_by_os(os: &str, command: Command) -> Result { let (shell, flag) = if WINDOWS.is(os) { - ("cmd", "/c") + ("powershell", "-c") } else { ("sh", "-c") }; From ad211e94119834efa1f53dd3caaf6121d370db1e Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Mon, 3 Mar 2025 17:30:33 +0100 Subject: [PATCH 02/12] [rust] Use multiple command in exec driver test --- rust/tests/common.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/tests/common.rs b/rust/tests/common.rs index e6190ef9bcd93..68bb2e647128b 100644 --- a/rust/tests/common.rs +++ b/rust/tests/common.rs @@ -76,7 +76,9 @@ pub fn get_driver_path(cmd: &mut Command) -> String { pub fn exec_driver(cmd: &mut Command) -> String { let cmd_mut = cmd.borrow_mut(); let driver_path = get_driver_path(cmd_mut); - let driver_version_command = shell::Command::new_single(format!("{} --version", &driver_path)); + let static_driver_path: &'static str = Box::leak(driver_path.into_boxed_str()); + let driver_version_command = + shell::Command::new_multiple(vec![static_driver_path, "--version"]); let output = run_shell_command_by_os(OS, driver_version_command).unwrap(); println!("**** EXEC DRIVER: {}", output); output From 723c509d45b46f07c6b0d0e4bc173ca19c5cf5f7 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Mon, 3 Mar 2025 23:12:20 +0100 Subject: [PATCH 03/12] Revert "[rust] Use multiple command in exec driver test" This reverts commit 802da7ae481bfc4371bd4ee64ccb3e6cde886e41. --- rust/tests/common.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/tests/common.rs b/rust/tests/common.rs index 68bb2e647128b..e6190ef9bcd93 100644 --- a/rust/tests/common.rs +++ b/rust/tests/common.rs @@ -76,9 +76,7 @@ pub fn get_driver_path(cmd: &mut Command) -> String { pub fn exec_driver(cmd: &mut Command) -> String { let cmd_mut = cmd.borrow_mut(); let driver_path = get_driver_path(cmd_mut); - let static_driver_path: &'static str = Box::leak(driver_path.into_boxed_str()); - let driver_version_command = - shell::Command::new_multiple(vec![static_driver_path, "--version"]); + let driver_version_command = shell::Command::new_single(format!("{} --version", &driver_path)); let output = run_shell_command_by_os(OS, driver_version_command).unwrap(); println!("**** EXEC DRIVER: {}", output); output From be150fee7efaee69c115476f381c9d08d18f7cc6 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Mon, 3 Mar 2025 23:19:27 +0100 Subject: [PATCH 04/12] [rust] Remove iexplorer exec test --- rust/tests/exec_driver_tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/tests/exec_driver_tests.rs b/rust/tests/exec_driver_tests.rs index da6db43ecb304..d83bdc4a1a200 100644 --- a/rust/tests/exec_driver_tests.rs +++ b/rust/tests/exec_driver_tests.rs @@ -26,7 +26,6 @@ mod common; #[case("chrome", "ChromeDriver")] #[case("edge", "Microsoft Edge WebDriver")] #[case("firefox", "geckodriver")] -#[case("iexplorer", "IEDriverServer")] fn exec_driver_test(#[case] browser_name: String, #[case] driver_name: String) { let mut cmd = get_selenium_manager(); cmd.args(["--browser", &browser_name, "--output", "json"]) From d769c53297d51b0b5268ca39fc3045d0b79bc103 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Mon, 3 Mar 2025 23:41:52 +0100 Subject: [PATCH 05/12] Revert "[rust] Remove iexplorer exec test" This reverts commit 91649aa33bb5113aea346cfacdaa16e5853630ef. --- rust/tests/exec_driver_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/tests/exec_driver_tests.rs b/rust/tests/exec_driver_tests.rs index d83bdc4a1a200..da6db43ecb304 100644 --- a/rust/tests/exec_driver_tests.rs +++ b/rust/tests/exec_driver_tests.rs @@ -26,6 +26,7 @@ mod common; #[case("chrome", "ChromeDriver")] #[case("edge", "Microsoft Edge WebDriver")] #[case("firefox", "geckodriver")] +#[case("iexplorer", "IEDriverServer")] fn exec_driver_test(#[case] browser_name: String, #[case] driver_name: String) { let mut cmd = get_selenium_manager(); cmd.args(["--browser", &browser_name, "--output", "json"]) From 0e901a0a7b95fc49b509ea5d75cfb43094d0b3e3 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Tue, 4 Mar 2025 00:01:06 +0100 Subject: [PATCH 06/12] [rust] Use PowerShell only for previous WMIC commands --- rust/src/files.rs | 4 ++-- rust/src/lib.rs | 28 ++++++++++++++++++---------- rust/src/shell.rs | 13 ++++++++++++- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/rust/src/files.rs b/rust/src/files.rs index 53753b93cb04f..8dc208a3cfb85 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -19,7 +19,7 @@ use crate::config::OS; use crate::config::OS::WINDOWS; use crate::{ format_one_arg, format_three_args, run_shell_command_by_os, Command, Logger, CP_VOLUME_COMMAND, - HDIUTIL_ATTACH_COMMAND, HDIUTIL_DETACH_COMMAND, MACOS, PS_MSIEXEC_INSTALL_COMMAND, + HDIUTIL_ATTACH_COMMAND, HDIUTIL_DETACH_COMMAND, MACOS, MSIEXEC_INSTALL_COMMAND, }; use anyhow::anyhow; use anyhow::Error; @@ -309,7 +309,7 @@ pub fn install_msi(msi_file: &str, log: &Logger, os: &str) -> Result<(), Error> msi_file_name.to_str().unwrap_or_default() )); - let command = Command::new_single(format_one_arg(PS_MSIEXEC_INSTALL_COMMAND, msi_file)); + let command = Command::new_single(format_one_arg(MSIEXEC_INSTALL_COMMAND, msi_file)); log.trace(format!("Running command: {}", command.display())); run_shell_command_by_os(os, command)?; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 9a1afb1ddeb14..53076c4a338ef 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -37,7 +37,8 @@ use crate::metadata::{ use crate::safari::{SafariManager, SAFARIDRIVER_NAME, SAFARI_NAME}; use crate::safaritp::{SafariTPManager, SAFARITP_NAMES}; use crate::shell::{ - run_shell_command, run_shell_command_by_os, run_shell_command_with_log, Command, + run_powershell_command_with_log, run_shell_command, run_shell_command_by_os, + run_shell_command_with_log, Command, }; use crate::stats::{send_stats_to_plausible, Props}; use anyhow::anyhow; @@ -77,8 +78,6 @@ pub const NIGHTLY: &str = "nightly"; pub const ESR: &str = "esr"; pub const PS_GET_VERSION_COMMAND: &str = r#"(Get-Item "{}").VersionInfo.ProductVersion"#; pub const PS_GET_OS_COMMAND: &str = "(Get-WmiObject Win32_OperatingSystem).OSArchitecture"; -pub const PS_MSIEXEC_INSTALL_COMMAND: &str = - r#"Start-Process -FilePath msiexec -ArgumentList "/i {} /qn ALLOWDOWNGRADE=1" -Wait"#; pub const REG_VERSION_ARG: &str = "version"; pub const REG_CURRENT_VERSION_ARG: &str = "CurrentVersion"; pub const REG_PV_ARG: &str = "pv"; @@ -87,6 +86,7 @@ pub const PLIST_COMMAND: &str = pub const HDIUTIL_ATTACH_COMMAND: &str = "hdiutil attach {}"; pub const HDIUTIL_DETACH_COMMAND: &str = "hdiutil detach /Volumes/{}"; pub const CP_VOLUME_COMMAND: &str = "cp -R /Volumes/{}/{}.app {}"; +pub const MSIEXEC_INSTALL_COMMAND: &str = "start /wait msiexec /i {} /qn ALLOWDOWNGRADE=1"; pub const WINDOWS_CHECK_ADMIN_COMMAND: &str = "net session"; pub const DASH_VERSION: &str = "{}{}{} -v"; pub const DASH_DASH_VERSION: &str = "{}{}{} --version"; @@ -448,14 +448,22 @@ pub trait SeleniumManager { )); let mut browser_version: Option = None; for driver_version_command in commands.into_iter() { - let output = match run_shell_command_with_log( - self.get_logger(), - self.get_os(), - driver_version_command, - ) { - Ok(out) => out, - Err(_e) => continue, + let output = if driver_version_command.display().starts_with("(Get-") { + match run_powershell_command_with_log(self.get_logger(), driver_version_command) { + Ok(out) => out, + Err(_e) => continue, + } + } else { + match run_shell_command_with_log( + self.get_logger(), + self.get_os(), + driver_version_command, + ) { + Ok(out) => out, + Err(_e) => continue, + } }; + let full_browser_version = parse_version(output, self.get_logger()).unwrap_or_default(); if full_browser_version.is_empty() { continue; diff --git a/rust/src/shell.rs b/rust/src/shell.rs index 9696eb509f59f..04e04e34622cd 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -64,6 +64,13 @@ impl Command { } } +pub fn run_powershell_command_with_log(log: &Logger, command: Command) -> Result { + log.debug(format!("Running command: {}", command.display())); + let output = run_powershell_command(command)?; + log.debug(format!("Output: {:?}", output)); + Ok(output) +} + pub fn run_shell_command_with_log( log: &Logger, os: &str, @@ -75,9 +82,13 @@ pub fn run_shell_command_with_log( Ok(output) } +pub fn run_powershell_command(command: Command) -> Result { + run_shell_command("powershell", "-c", command) +} + pub fn run_shell_command_by_os(os: &str, command: Command) -> Result { let (shell, flag) = if WINDOWS.is(os) { - ("powershell", "-c") + ("cmd", "/c") } else { ("sh", "-c") }; From 3e26123fd5d5e9f2998ebf1ffa7b1d62e6a021ea Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Tue, 4 Mar 2025 00:17:04 +0100 Subject: [PATCH 07/12] [rust] Run PS command to discover OS --- rust/src/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/config.rs b/rust/src/config.rs index b4feaa9ca3a83..47bdfa8647e43 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -16,7 +16,7 @@ // under the License. use crate::config::OS::{LINUX, MACOS, WINDOWS}; -use crate::shell::run_shell_command_by_os; +use crate::shell::{run_powershell_command, run_shell_command_by_os}; use crate::{ default_cache_folder, format_one_arg, path_to_string, Command, ENV_PROCESSOR_ARCHITECTURE, REQUEST_TIMEOUT_SEC, UNAME_COMMAND, @@ -71,8 +71,8 @@ impl ManagerConfig { let self_arch = if WINDOWS.is(self_os) { let mut architecture = env::var(ENV_PROCESSOR_ARCHITECTURE).unwrap_or_default(); if architecture.is_empty() { - let get_os_command = Command::new_single(WMIC_COMMAND_OS.to_string()); - architecture = run_shell_command_by_os(self_os, get_os_command).unwrap_or_default(); + let get_os_command = Command::new_single(PS_GET_OS_COMMAND.to_string()); + architecture = run_powershell_command(get_os_command).unwrap_or_default(); } if architecture.contains("32") { ARCH_X86.to_string() From 258d3da179c4a95e93706ac6ca2e271c3e97579b Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Tue, 4 Mar 2025 00:37:09 +0100 Subject: [PATCH 08/12] [rust] Setup PROCESSOR_ARCHITECTURE env for Windows --- rust/src/shell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/shell.rs b/rust/src/shell.rs index 04e04e34622cd..8857bd003bc47 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -65,7 +65,7 @@ impl Command { } pub fn run_powershell_command_with_log(log: &Logger, command: Command) -> Result { - log.debug(format!("Running command: {}", command.display())); + log.debug(format!("Running ps command: {}", command.display())); let output = run_powershell_command(command)?; log.debug(format!("Output: {:?}", output)); Ok(output) From 50c6c132a234e402515a9f8d0f77aac21db1766e Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Tue, 4 Mar 2025 01:27:43 +0100 Subject: [PATCH 09/12] [rust] Avoid repetition in logic to run powershell or not --- rust/src/lib.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 53076c4a338ef..c196d7541b8c2 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -448,20 +448,14 @@ pub trait SeleniumManager { )); let mut browser_version: Option = None; for driver_version_command in commands.into_iter() { - let output = if driver_version_command.display().starts_with("(Get-") { - match run_powershell_command_with_log(self.get_logger(), driver_version_command) { - Ok(out) => out, - Err(_e) => continue, - } + let command_result = if driver_version_command.display().starts_with("(Get-") { + run_powershell_command_with_log(self.get_logger(), driver_version_command) } else { - match run_shell_command_with_log( - self.get_logger(), - self.get_os(), - driver_version_command, - ) { - Ok(out) => out, - Err(_e) => continue, - } + run_shell_command_with_log(self.get_logger(), self.get_os(), driver_version_command) + }; + let output = match command_result { + Ok(out) => out, + Err(_) => continue, }; let full_browser_version = parse_version(output, self.get_logger()).unwrap_or_default(); From 49ea513279a9c12a3032f4329af80909b4ebd911 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Wed, 7 May 2025 20:58:33 +0200 Subject: [PATCH 10/12] Use winapi instead of PowerShell to discover browser version --- rust/Cargo.lock | 1 + rust/Cargo.toml | 1 + rust/src/config.rs | 29 +++++++++++++--- rust/src/files.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++ rust/src/lib.rs | 23 +++++-------- rust/src/shell.rs | 11 ------- 6 files changed, 117 insertions(+), 30 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c616fc119dbed..96f9a5ef26d2f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1866,6 +1866,7 @@ dependencies = [ "toml", "walkdir", "which", + "winapi", "xz2", "zip", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index e04305650c819..2ca5cf46081d6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -38,6 +38,7 @@ apple-flat-package = "0.20.0" which = "7.0.2" fs2 = "0.4.3" fs_extra = "1.3.0" +winapi = { version = "0.3.9", features = ["winver", "winnt", "sysinfoapi"] } [dev-dependencies] assert_cmd = "2.0.16" diff --git a/rust/src/config.rs b/rust/src/config.rs index 47bdfa8647e43..83aa294f38b3a 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -16,12 +16,12 @@ // under the License. use crate::config::OS::{LINUX, MACOS, WINDOWS}; -use crate::shell::{run_powershell_command, run_shell_command_by_os}; +use crate::shell::run_shell_command_by_os; use crate::{ default_cache_folder, format_one_arg, path_to_string, Command, ENV_PROCESSOR_ARCHITECTURE, REQUEST_TIMEOUT_SEC, UNAME_COMMAND, }; -use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, PS_GET_OS_COMMAND, TTL_SEC}; +use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, TTL_SEC}; use anyhow::anyhow; use anyhow::Error; use std::cell::RefCell; @@ -30,6 +30,11 @@ use std::env::consts::OS; use std::fs::read_to_string; use std::path::Path; use toml::Table; +use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO}; +use winapi::um::winnt::{ + PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARCHITECTURE_ARM64, + PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_INTEL, +}; thread_local!(static CACHE_PATH: RefCell = RefCell::new(path_to_string(&default_cache_folder()))); @@ -71,8 +76,7 @@ impl ManagerConfig { let self_arch = if WINDOWS.is(self_os) { let mut architecture = env::var(ENV_PROCESSOR_ARCHITECTURE).unwrap_or_default(); if architecture.is_empty() { - let get_os_command = Command::new_single(PS_GET_OS_COMMAND.to_string()); - architecture = run_powershell_command(get_os_command).unwrap_or_default(); + architecture = get_win_os_architecture(); } if architecture.contains("32") { ARCH_X86.to_string() @@ -297,3 +301,20 @@ fn read_cache_path() -> String { }); cache_path } + +fn get_win_os_architecture() -> String { + unsafe { + let mut system_info: SYSTEM_INFO = std::mem::zeroed(); + GetNativeSystemInfo(&mut system_info); + + match system_info.u.s() { + si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 => "64-bit", + si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL => "32-bit", + si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM => "ARM", + si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64 => "ARM64", + si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 => "Itanium-based", + _ => "Unknown", + } + .to_string() + } +} diff --git a/rust/src/files.rs b/rust/src/files.rs index 8dc208a3cfb85..eacca677a8476 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -29,13 +29,18 @@ use directories::BaseDirs; use flate2::read::GzDecoder; use fs_extra::dir::{move_dir, CopyOptions}; use regex::Regex; +use std::ffi::OsStr; use std::fs; use std::fs::File; use std::io; use std::io::{BufReader, Cursor, Read}; +use std::os::windows::ffi::OsStrExt; use std::path::{Path, PathBuf}; +use std::ptr; use tar::Archive; use walkdir::{DirEntry, WalkDir}; +use winapi::shared::minwindef::LPVOID; +use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW}; use xz2::read::XzDecoder; use zip::ZipArchive; @@ -594,3 +599,80 @@ pub fn capitalize(s: &str) -> String { Some(first) => first.to_uppercase().collect::() + chars.as_str(), } } + +pub fn get_win_file_version(file_path: &str) -> Option { + unsafe { + let wide_path: Vec = OsStr::new(file_path).encode_wide().chain(Some(0)).collect(); + + let mut dummy = 0; + let size = GetFileVersionInfoSizeW(wide_path.as_ptr(), &mut dummy); + if size == 0 { + return None; + } + + let mut buffer: Vec = Vec::with_capacity(size as usize); + if GetFileVersionInfoW(wide_path.as_ptr(), 0, size, buffer.as_mut_ptr() as LPVOID) == 0 { + return None; + } + buffer.set_len(size as usize); + + let mut lang_and_codepage_ptr: LPVOID = ptr::null_mut(); + let mut lang_and_codepage_len: u32 = 0; + + if VerQueryValueW( + buffer.as_ptr() as LPVOID, + OsStr::new("\\VarFileInfo\\Translation") + .encode_wide() + .chain(Some(0)) + .collect::>() + .as_ptr(), + &mut lang_and_codepage_ptr, + &mut lang_and_codepage_len, + ) == 0 + { + return None; + } + + if lang_and_codepage_len == 0 { + return None; + } + + let lang_and_codepage_slice = std::slice::from_raw_parts( + lang_and_codepage_ptr as *const u16, + lang_and_codepage_len as usize / 2, + ); + let lang = lang_and_codepage_slice[0]; + let codepage = lang_and_codepage_slice[1]; + + let query = format!( + "\\StringFileInfo\\{:04x}{:04x}\\ProductVersion", + lang, codepage + ); + let query_wide: Vec = OsStr::new(&query).encode_wide().chain(Some(0)).collect(); + + let mut product_version_ptr: LPVOID = ptr::null_mut(); + let mut product_version_len: u32 = 0; + + if VerQueryValueW( + buffer.as_ptr() as LPVOID, + query_wide.as_ptr(), + &mut product_version_ptr, + &mut product_version_len, + ) == 0 + { + return None; + } + + if product_version_ptr.is_null() { + return None; + } + + let product_version_slice = std::slice::from_raw_parts( + product_version_ptr as *const u16, + product_version_len as usize, + ); + let product_version = String::from_utf16_lossy(product_version_slice); + + Some(product_version.trim_end_matches('\0').to_string()) + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c196d7541b8c2..9f367a5528d98 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -20,6 +20,7 @@ use crate::config::OS::{MACOS, WINDOWS}; use crate::config::{str_to_os, ManagerConfig}; use crate::downloads::download_to_tmp_folder; use crate::edge::{EdgeManager, EDGEDRIVER_NAME, EDGE_NAMES, WEBVIEW2_NAME}; +use crate::files::get_win_file_version; use crate::files::{ capitalize, collect_files_from_cache, create_path_if_not_exists, default_cache_folder, find_latest_from_cache, get_binary_extension, path_to_string, @@ -37,8 +38,7 @@ use crate::metadata::{ use crate::safari::{SafariManager, SAFARIDRIVER_NAME, SAFARI_NAME}; use crate::safaritp::{SafariTPManager, SAFARITP_NAMES}; use crate::shell::{ - run_powershell_command_with_log, run_shell_command, run_shell_command_by_os, - run_shell_command_with_log, Command, + run_shell_command, run_shell_command_by_os, run_shell_command_with_log, Command, }; use crate::stats::{send_stats_to_plausible, Props}; use anyhow::anyhow; @@ -76,8 +76,6 @@ pub const DEV: &str = "dev"; pub const CANARY: &str = "canary"; pub const NIGHTLY: &str = "nightly"; pub const ESR: &str = "esr"; -pub const PS_GET_VERSION_COMMAND: &str = r#"(Get-Item "{}").VersionInfo.ProductVersion"#; -pub const PS_GET_OS_COMMAND: &str = "(Get-WmiObject Win32_OperatingSystem).OSArchitecture"; pub const REG_VERSION_ARG: &str = "version"; pub const REG_CURRENT_VERSION_ARG: &str = "CurrentVersion"; pub const REG_PV_ARG: &str = "pv"; @@ -448,12 +446,11 @@ pub trait SeleniumManager { )); let mut browser_version: Option = None; for driver_version_command in commands.into_iter() { - let command_result = if driver_version_command.display().starts_with("(Get-") { - run_powershell_command_with_log(self.get_logger(), driver_version_command) - } else { - run_shell_command_with_log(self.get_logger(), self.get_os(), driver_version_command) - }; - let output = match command_result { + let output = match run_shell_command_with_log( + self.get_logger(), + self.get_os(), + driver_version_command, + ) { Ok(out) => out, Err(_) => continue, }; @@ -1161,11 +1158,7 @@ pub trait SeleniumManager { let mut commands = Vec::new(); if WINDOWS.is(self.get_os()) { if !escaped_browser_path.is_empty() { - let get_version_command = Command::new_single(format_one_arg( - PS_GET_VERSION_COMMAND, - &escaped_browser_path, - )); - commands.push(get_version_command); + return Ok(get_win_file_version(&escaped_browser_path)); } if !self.is_browser_version_unstable() { let reg_command = diff --git a/rust/src/shell.rs b/rust/src/shell.rs index 8857bd003bc47..203ba693a8924 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -64,13 +64,6 @@ impl Command { } } -pub fn run_powershell_command_with_log(log: &Logger, command: Command) -> Result { - log.debug(format!("Running ps command: {}", command.display())); - let output = run_powershell_command(command)?; - log.debug(format!("Output: {:?}", output)); - Ok(output) -} - pub fn run_shell_command_with_log( log: &Logger, os: &str, @@ -82,10 +75,6 @@ pub fn run_shell_command_with_log( Ok(output) } -pub fn run_powershell_command(command: Command) -> Result { - run_shell_command("powershell", "-c", command) -} - pub fn run_shell_command_by_os(os: &str, command: Command) -> Result { let (shell, flag) = if WINDOWS.is(os) { ("cmd", "/c") From 624396161e4ef2537c2a2e3f08617eb639e26e47 Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Wed, 7 May 2025 21:07:17 +0200 Subject: [PATCH 11/12] Update checksum in Cargo.Bazel.lock --- rust/Cargo.Bazel.lock | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index b8778dd03b8f1..c4c994fad5606 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "d2d968dacd2ceab962c18fa28697dc189f31b3991a3554ff21e167836627a3b8", + "checksum": "94dc89c8790518c956fd52cd06689af1557f6c755c7bd1a1414719ef73ac468c", "crates": { "addr2line 0.21.0": { "name": "addr2line", @@ -13478,6 +13478,10 @@ "id": "which 7.0.2", "target": "which" }, + { + "id": "winapi 0.3.9", + "target": "winapi" + }, { "id": "xz2 0.1.7", "target": "xz2" @@ -18838,14 +18842,36 @@ ], "crate_features": { "common": [ - "fileapi", - "handleapi", - "processthreadsapi", - "std", - "winbase", - "winerror" + "sysinfoapi", + "winnt", + "winver" ], - "selects": {} + "selects": { + "aarch64-pc-windows-msvc": [ + "fileapi", + "handleapi", + "processthreadsapi", + "std", + "winbase", + "winerror" + ], + "i686-pc-windows-msvc": [ + "fileapi", + "handleapi", + "processthreadsapi", + "std", + "winbase", + "winerror" + ], + "x86_64-pc-windows-msvc": [ + "fileapi", + "handleapi", + "processthreadsapi", + "std", + "winbase", + "winerror" + ] + } }, "deps": { "common": [ @@ -21972,6 +21998,7 @@ "toml 0.8.20", "walkdir 2.5.0", "which 7.0.2", + "winapi 0.3.9", "xz2 0.1.7", "zip 2.2.3" ], From c3697595d5f71fb276654ebc3d2f7ad6df60a7fe Mon Sep 17 00:00:00 2001 From: Boni Garcia Date: Thu, 8 May 2025 17:30:43 +0200 Subject: [PATCH 12/12] Use conditional compilation for winapi logic (only compiled in Windows) --- rust/src/config.rs | 16 +++++++++++----- rust/src/files.rs | 11 +++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/rust/src/config.rs b/rust/src/config.rs index 83aa294f38b3a..74dbb0abbf2f8 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -30,7 +30,9 @@ use std::env::consts::OS; use std::fs::read_to_string; use std::path::Path; use toml::Table; +#[cfg(windows)] use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO}; +#[cfg(windows)] use winapi::um::winnt::{ PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARCHITECTURE_ARM64, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_INTEL, @@ -74,13 +76,16 @@ impl ManagerConfig { let self_os = OS; let self_arch = if WINDOWS.is(self_os) { - let mut architecture = env::var(ENV_PROCESSOR_ARCHITECTURE).unwrap_or_default(); - if architecture.is_empty() { - architecture = get_win_os_architecture(); + let mut _architecture = env::var(ENV_PROCESSOR_ARCHITECTURE).unwrap_or_default(); + #[cfg(windows)] + { + if _architecture.is_empty() { + _architecture = get_win_os_architecture(); + } } - if architecture.contains("32") { + if _architecture.contains("32") { ARCH_X86.to_string() - } else if architecture.contains("ARM") { + } else if _architecture.contains("ARM") { ARCH_ARM64.to_string() } else { ARCH_AMD64.to_string() @@ -302,6 +307,7 @@ fn read_cache_path() -> String { cache_path } +#[cfg(windows)] fn get_win_os_architecture() -> String { unsafe { let mut system_info: SYSTEM_INFO = std::mem::zeroed(); diff --git a/rust/src/files.rs b/rust/src/files.rs index eacca677a8476..5f3679bc96575 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -29,17 +29,22 @@ use directories::BaseDirs; use flate2::read::GzDecoder; use fs_extra::dir::{move_dir, CopyOptions}; use regex::Regex; +#[cfg(windows)] use std::ffi::OsStr; use std::fs; use std::fs::File; use std::io; use std::io::{BufReader, Cursor, Read}; +#[cfg(windows)] use std::os::windows::ffi::OsStrExt; use std::path::{Path, PathBuf}; +#[cfg(windows)] use std::ptr; use tar::Archive; use walkdir::{DirEntry, WalkDir}; +#[cfg(windows)] use winapi::shared::minwindef::LPVOID; +#[cfg(windows)] use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW}; use xz2::read::XzDecoder; use zip::ZipArchive; @@ -600,6 +605,12 @@ pub fn capitalize(s: &str) -> String { } } +#[cfg(not(windows))] +pub fn get_win_file_version(_file_path: &str) -> Option { + None +} + +#[cfg(windows)] pub fn get_win_file_version(file_path: &str) -> Option { unsafe { let wide_path: Vec = OsStr::new(file_path).encode_wide().chain(Some(0)).collect();