diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index 8188b66f1681c..157ca2f9a2622 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "7bb62c0cb24820374fb08c7eb1d2c1661ceb1a296f8cf2cad91579a7d2687eaf", + "checksum": "d9d5f22625fe3080b3eef8acfa5d55ae7929945c9570e4d592189d3b69f4149f", "crates": { "addr2line 0.19.0": { "name": "addr2line", @@ -478,6 +478,71 @@ }, "license": "MIT OR Apache-2.0" }, + "anyhow 1.0.75": { + "name": "anyhow", + "version": "1.0.75", + "repository": { + "Http": { + "url": "https://crates.io/api/v1/crates/anyhow/1.0.75/download", + "sha256": "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + } + }, + "targets": [ + { + "Library": { + "crate_name": "anyhow", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "anyhow", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "backtrace", + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "anyhow 1.0.75", + "target": "build_script_build" + }, + { + "id": "backtrace 0.3.67", + "target": "backtrace" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.75" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0" + }, "ar 0.9.0": { "name": "ar", "version": "0.9.0", @@ -672,6 +737,13 @@ "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, "deps": { "common": [ { @@ -3860,6 +3932,13 @@ "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "read", + "read-core" + ], + "selects": {} + }, "edition": "2018", "version": "0.27.3" }, @@ -5965,6 +6044,18 @@ "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "archive", + "coff", + "elf", + "macho", + "pe", + "read_core", + "unaligned" + ], + "selects": {} + }, "deps": { "common": [ { @@ -8003,6 +8094,10 @@ ], "deps": { "common": [ + { + "id": "anyhow 1.0.75", + "target": "anyhow" + }, { "id": "bzip2 0.4.4", "target": "bzip2" diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f1cf6b94a6b64..cea7175ac3f44 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -98,6 +98,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +dependencies = [ + "backtrace", +] + [[package]] name = "ar" version = "0.9.0" @@ -1492,6 +1501,7 @@ dependencies = [ name = "selenium-manager" version = "0.4.14" dependencies = [ + "anyhow", "assert_cmd", "bzip2", "clap", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1fe680ee5a0a4..77a59190dba90 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -33,6 +33,7 @@ bzip2 = "0.4.4" sevenz-rust = "0.5.2" walkdir = "2.4.0" debpkg = "0.6.0" +anyhow = { version = "1.0.75", features = ["backtrace"] } [dev-dependencies] assert_cmd = "2.0.12" diff --git a/rust/src/chrome.rs b/rust/src/chrome.rs index 54692ee4f5c65..36cd958e951e9 100644 --- a/rust/src/chrome.rs +++ b/rust/src/chrome.rs @@ -19,7 +19,9 @@ use crate::config::ManagerConfig; use reqwest::Client; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; +use anyhow::Error; use std::option::Option; use std::path::PathBuf; @@ -60,7 +62,7 @@ pub struct ChromeManager { } impl ChromeManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = CHROME_NAME; let driver_name = CHROMEDRIVER_NAME; let config = ManagerConfig::default(browser_name, driver_name); @@ -94,10 +96,7 @@ impl ChromeManager { format!("{}{}", CFT_URL, endpoint) } - fn request_driver_version_from_latest( - &self, - driver_url: String, - ) -> Result> { + fn request_driver_version_from_latest(&self, driver_url: String) -> Result { self.log.debug(format!( "Reading {} version from {}", &self.driver_name, driver_url @@ -105,7 +104,7 @@ impl ChromeManager { read_version_from_link(self.get_http_client(), driver_url, self.get_logger()) } - fn request_versions_from_online(&self, driver_url: String) -> Result> + fn request_versions_from_online(&self, driver_url: String) -> Result where T: Serialize + for<'a> Deserialize<'a>, { @@ -114,7 +113,7 @@ impl ChromeManager { parse_json_from_url::(self.get_http_client(), driver_url) } - fn request_latest_driver_version_from_online(&mut self) -> Result> { + fn request_latest_driver_version_from_online(&mut self) -> Result { let driver_name = self.driver_name; self.get_logger().trace(format!( "Using Chrome for Testing (CfT) endpoints to find out latest stable {} version", @@ -150,7 +149,7 @@ impl ChromeManager { Ok(stable_channel.version) } - fn request_good_driver_version_from_online(&mut self) -> Result> { + fn request_good_driver_version_from_online(&mut self) -> Result { let browser_or_driver_version = if self.get_driver_version().is_empty() { self.get_browser_version() } else { @@ -170,13 +169,12 @@ impl ChromeManager { .filter(|r| r.version.starts_with(version_for_filtering.as_str())) .collect(); if filtered_versions.is_empty() { - return Err(format_three_args( + return Err(anyhow!(format_three_args( UNAVAILABLE_DOWNLOAD_WITH_MIN_VERSION_ERR_MSG, self.get_driver_name(), &version_for_filtering, &MIN_CHROMEDRIVER_VERSION_CFT.to_string(), - ) - .into()); + ))); } let driver_version = filtered_versions.last().unwrap(); @@ -255,7 +253,7 @@ impl SeleniumManager for ChromeManager { ]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.general_discover_browser_version( r#"HKCU\Software\Google\Chrome\BLBeacon"#, REG_VERSION_ARG, @@ -267,7 +265,7 @@ impl SeleniumManager for ChromeManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { let major_browser_version_binding = self.get_major_browser_version(); let major_browser_version = major_browser_version_binding.as_str(); let cache_path = self.get_cache_path()?; @@ -327,11 +325,11 @@ impl SeleniumManager for ChromeManager { } } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { self.general_request_browser_version(self.browser_name) } - fn get_driver_url(&mut self) -> Result> { + fn get_driver_url(&mut self) -> Result { let major_driver_version = self .get_major_driver_version() .parse::() @@ -373,7 +371,7 @@ impl SeleniumManager for ChromeManager { )) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(compose_driver_path_in_cache( self.get_cache_path()?.unwrap_or_default(), self.driver_name, @@ -426,7 +424,7 @@ impl SeleniumManager for ChromeManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { let browser_name = self.browser_name; self.get_logger().trace(format!( "Using Chrome for Testing (CfT) endpoints to find out latest stable {} version", @@ -457,7 +455,7 @@ impl SeleniumManager for ChromeManager { fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { let browser_name = self.browser_name; let mut browser_version = self.get_browser_version().to_string(); let major_browser_version = self.get_major_browser_version(); @@ -497,13 +495,12 @@ impl SeleniumManager for ChromeManager { .filter(|r| r.version.starts_with(major_browser_version.as_str())) .collect(); if filtered_versions.is_empty() { - return Err(format_three_args( + return Err(anyhow!(format_three_args( UNAVAILABLE_DOWNLOAD_WITH_MIN_VERSION_ERR_MSG, browser_name, &major_browser_version, &MIN_CHROME_VERSION_CFT.to_string(), - ) - .into()); + ))); } let last_browser = filtered_versions.last().unwrap(); let platform_url: Vec<&PlatformUrl> = last_browser @@ -518,14 +515,11 @@ impl SeleniumManager for ChromeManager { } } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { Ok(MIN_CHROME_VERSION_CFT) } - fn get_browser_binary_path( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result { let browser_in_cache = self.get_browser_path_in_cache()?; if MACOS.is(self.get_os()) { Ok(browser_in_cache.join(CFT_MACOS_APP_NAME)) @@ -534,10 +528,7 @@ impl SeleniumManager for ChromeManager { } } - fn get_browser_url_for_download( - &mut self, - browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result { if let Some(browser_url) = self.browser_url.clone() { Ok(browser_url) } else { @@ -553,7 +544,7 @@ impl SeleniumManager for ChromeManager { fn get_browser_label_for_download( &self, _browser_version: &str, - ) -> Result, Box> { + ) -> Result, Error> { Ok(None) } } diff --git a/rust/src/config.rs b/rust/src/config.rs index 5b217b6c426d6..ec4d65659e429 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -25,7 +25,9 @@ use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, TTL_SEC, WMIC_COMMAND_OS}; use std::cell::RefCell; use std::env; use std::env::consts::OS; -use std::error::Error; + +use anyhow::anyhow; +use anyhow::Error; use std::fs::read_to_string; use std::path::Path; use toml::Table; @@ -129,7 +131,7 @@ impl OS { } } -pub fn str_to_os(os: &str) -> Result> { +pub fn str_to_os(os: &str) -> Result { if WINDOWS.is(os) { Ok(WINDOWS) } else if MACOS.is(os) { @@ -137,7 +139,7 @@ pub fn str_to_os(os: &str) -> Result> { } else if LINUX.is(os) { Ok(LINUX) } else { - Err(format!("Invalid operating system: {os}").into()) + Err(anyhow!(format!("Invalid operating system: {os}"))) } } @@ -232,7 +234,7 @@ fn get_env_name(suffix: &str) -> String { concat(ENV_PREFIX, suffix_uppercase.as_str()) } -fn get_config() -> Result> { +fn get_config() -> Result { let cache_path = read_cache_path(); let config_path = Path::new(&cache_path).to_path_buf().join(CONFIG_FILE); Ok(read_to_string(config_path)?.parse()?) diff --git a/rust/src/downloads.rs b/rust/src/downloads.rs index a5d5ea8f83978..d72f4be4b77c0 100644 --- a/rust/src/downloads.rs +++ b/rust/src/downloads.rs @@ -15,10 +15,12 @@ // specific language governing permissions and limitations // under the License. +use anyhow::Error; use reqwest::{Client, StatusCode}; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::error::Error; + +use anyhow::anyhow; use std::fs::File; use std::io::copy; use std::io::Cursor; @@ -33,7 +35,7 @@ pub async fn download_to_tmp_folder( http_client: &Client, url: String, log: &Logger, -) -> Result<(TempDir, String), Box> { +) -> Result<(TempDir, String), Error> { let tmp_dir = Builder::new().prefix("selenium-manager").tempdir()?; log.trace(format!( "Downloading {} to temporal folder {:?}", @@ -44,7 +46,10 @@ pub async fn download_to_tmp_folder( let response = http_client.get(&url).send().await?; let status_code = response.status(); if status_code != StatusCode::OK { - return Err(format!("Unsuccessful response ({}) for URL {}", status_code, url).into()); + return Err(anyhow!(format!( + "Unsuccessful response ({}) for URL {}", + status_code, url + ))); } let target_path; @@ -76,15 +81,12 @@ pub fn read_version_from_link( http_client: &Client, url: String, log: &Logger, -) -> Result> { +) -> Result { parse_version(read_content_from_link(http_client, url)?, log) } #[tokio::main] -pub async fn read_content_from_link( - http_client: &Client, - url: String, -) -> Result> { +pub async fn read_content_from_link(http_client: &Client, url: String) -> Result { Ok(http_client.get(url).send().await?.text().await?) } @@ -93,14 +95,14 @@ pub async fn read_redirect_from_link( http_client: &Client, url: String, log: &Logger, -) -> Result> { +) -> Result { parse_version( http_client.get(&url).send().await?.url().path().to_string(), log, ) } -pub fn parse_json_from_url(http_client: &Client, url: String) -> Result> +pub fn parse_json_from_url(http_client: &Client, url: String) -> Result where T: Serialize + for<'a> Deserialize<'a>, { @@ -109,10 +111,7 @@ where Ok(response) } -pub fn parse_generic_json_from_url( - http_client: &Client, - url: String, -) -> Result> { +pub fn parse_generic_json_from_url(http_client: &Client, url: String) -> Result { let content = read_content_from_link(http_client, url)?; let response: Value = serde_json::from_str(&content)?; Ok(response) diff --git a/rust/src/edge.rs b/rust/src/edge.rs index 2913f20ec1227..97cf2ff979573 100644 --- a/rust/src/edge.rs +++ b/rust/src/edge.rs @@ -16,11 +16,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; -use std::error::Error; use std::path::{Path, PathBuf}; use crate::config::ARCH::{ARM64, X32}; @@ -60,7 +60,7 @@ pub struct EdgeManager { } impl EdgeManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = EDGE_NAMES[0]; let driver_name = EDGEDRIVER_NAME; let config = ManagerConfig::default(browser_name, driver_name); @@ -137,7 +137,7 @@ impl SeleniumManager for EdgeManager { ]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.general_discover_browser_version( r#"HKCU\Software\Microsoft\Edge\BLBeacon"#, REG_VERSION_ARG, @@ -149,7 +149,7 @@ impl SeleniumManager for EdgeManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { let mut major_browser_version = self.get_major_browser_version(); let cache_path = self.get_cache_path()?; let mut metadata = get_metadata(self.get_logger(), &cache_path); @@ -220,11 +220,11 @@ impl SeleniumManager for EdgeManager { } } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { Ok(None) } - fn get_driver_url(&mut self) -> Result> { + fn get_driver_url(&mut self) -> Result { let driver_version = self.get_driver_version(); let os = self.get_os(); let arch = self.get_arch(); @@ -251,7 +251,7 @@ impl SeleniumManager for EdgeManager { )) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(compose_driver_path_in_cache( self.get_cache_path()?.unwrap_or_default(), self.driver_name, @@ -306,7 +306,7 @@ impl SeleniumManager for EdgeManager { fn request_latest_browser_version_from_online( &mut self, browser_version: &str, - ) -> Result> { + ) -> Result { let browser_name = self.browser_name; let is_fixed_browser_version = !self.is_empty(browser_version) && !self.is_stable(browser_version) @@ -412,18 +412,15 @@ impl SeleniumManager for EdgeManager { fn request_fixed_browser_version_from_online( &mut self, browser_version: &str, - ) -> Result> { + ) -> Result { self.request_latest_browser_version_from_online(browser_version) } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { Ok(MIN_EDGE_VERSION_DOWNLOAD) } - fn get_browser_binary_path( - &mut self, - browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, browser_version: &str) -> Result { let browser_in_cache = self.get_browser_path_in_cache()?; if MACOS.is(self.get_os()) { let macos_app_name = if self.is_beta(browser_version) { @@ -462,20 +459,14 @@ impl SeleniumManager for EdgeManager { } } - fn get_browser_url_for_download( - &mut self, - browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result { if self.browser_url.is_none() { self.request_latest_browser_version_from_online(browser_version)?; } Ok(self.browser_url.clone().unwrap()) } - fn get_browser_label_for_download( - &self, - browser_version: &str, - ) -> Result, Box> { + fn get_browser_label_for_download(&self, browser_version: &str) -> Result, Error> { let browser_label = if self.is_beta(browser_version) { "msedge-beta" } else if self.is_dev(browser_version) { diff --git a/rust/src/files.rs b/rust/src/files.rs index 2eff09e160ad6..570e06f1004de 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -15,12 +15,13 @@ // specific language governing permissions and limitations // under the License. -use std::error::Error; +use anyhow::Error; use std::fs; use std::fs::File; use std::io; use std::io::{BufReader, Cursor, Read}; +use anyhow::anyhow; use bzip2::read::BzDecoder; use std::path::{Path, PathBuf}; @@ -69,7 +70,7 @@ impl BrowserPath { } } -pub fn create_empty_parent_path_if_not_exists(path: &Path) -> Result<(), Box> { +pub fn create_empty_parent_path_if_not_exists(path: &Path) -> Result<(), Error> { if let Some(p) = path.parent() { create_path_if_not_exists(p)?; fs::remove_dir_all(p).and_then(|_| fs::create_dir(p))?; @@ -77,14 +78,14 @@ pub fn create_empty_parent_path_if_not_exists(path: &Path) -> Result<(), Box Result<(), Box> { +pub fn create_parent_path_if_not_exists(path: &Path) -> Result<(), Error> { if let Some(p) = path.parent() { create_path_if_not_exists(p)?; } Ok(()) } -pub fn create_path_if_not_exists(path: &Path) -> Result<(), Box> { +pub fn create_path_if_not_exists(path: &Path) -> Result<(), Error> { if !path.exists() { fs::create_dir_all(path)?; } @@ -99,7 +100,7 @@ pub fn uncompress( single_file: Option, volume: Option<&str>, major_browser_version: Option, -) -> Result<(), Box> { +) -> Result<(), Error> { let mut extension = match infer::get_from_path(compressed_file)? { Some(kind) => kind.extension(), _ => { @@ -107,12 +108,13 @@ pub fn uncompress( if MACOS.is(os) { PKG } else { - return Err(format_one_arg(UNCOMPRESS_MACOS_ERR_MSG, PKG).into()); + return Err(anyhow!(format_one_arg(UNCOMPRESS_MACOS_ERR_MSG, PKG))); } } else { - return Err( - format!("Format for file {} cannot be inferred", compressed_file).into(), - ); + return Err(anyhow!(format!( + "Format for file {} cannot be inferred", + compressed_file + ))); } } }; @@ -120,7 +122,7 @@ pub fn uncompress( if MACOS.is(os) { extension = DMG; } else { - return Err(format_one_arg(UNCOMPRESS_MACOS_ERR_MSG, DMG).into()); + return Err(anyhow!(format_one_arg(UNCOMPRESS_MACOS_ERR_MSG, DMG))); } } log.trace(format!( @@ -155,22 +157,17 @@ pub fn uncompress( "Wrong downloaded driver: {}", fs::read_to_string(compressed_file).unwrap_or_default() )); - return Err(PARSE_ERROR.into()); + return Err(anyhow!(PARSE_ERROR)); } else { - return Err(format!( + return Err(anyhow!(format!( "Downloaded file cannot be uncompressed ({} extension)", extension - ) - .into()); + ))); } Ok(()) } -pub fn uncompress_sfx( - compressed_file: &str, - target: &Path, - log: &Logger, -) -> Result<(), Box> { +pub fn uncompress_sfx(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), Error> { let zip_parent = Path::new(compressed_file).parent().unwrap(); log.trace(format!( "Decompressing {} to {}", @@ -180,7 +177,7 @@ pub fn uncompress_sfx( let file_bytes = read_bytes_from_file(compressed_file)?; let header = find_bytes(&file_bytes, SEVEN_ZIP_HEADER); - let index_7z = header.ok_or("Incorrect SFX (self extracting exe) file")?; + let index_7z = header.ok_or(anyhow!("Incorrect SFX (self extracting exe) file"))?; let file_reader = Cursor::new(&file_bytes[index_7z..]); sevenz_rust::decompress(file_reader, zip_parent).unwrap(); @@ -203,7 +200,7 @@ pub fn uncompress_pkg( log: &Logger, os: &str, major_browser_version: i32, -) -> Result<(), Box> { +) -> Result<(), Error> { let tmp_dir = Builder::new().prefix(PKG).tempdir()?; let out_folder = format!("{}/{}", path_to_string(tmp_dir.path()), PKG); let mut command = Command::new_single(format_two_args( @@ -242,7 +239,7 @@ pub fn uncompress_dmg( log: &Logger, os: &str, volume: &str, -) -> Result<(), Box> { +) -> Result<(), Error> { let dmg_file_name = Path::new(compressed_file) .file_name() .unwrap_or_default() @@ -278,7 +275,7 @@ pub fn uncompress_deb( target: &Path, log: &Logger, label: &str, -) -> Result<(), Box> { +) -> Result<(), Error> { let zip_parent = Path::new(compressed_file).parent().unwrap(); log.trace(format!( "Extracting from {} to {}", @@ -303,7 +300,7 @@ pub fn uncompress_deb( Ok(()) } -pub fn install_msi(msi_file: &str, log: &Logger, os: &str) -> Result<(), Box> { +pub fn install_msi(msi_file: &str, log: &Logger, os: &str) -> Result<(), Error> { let msi_file_name = Path::new(msi_file) .file_name() .unwrap_or_default() @@ -320,7 +317,7 @@ pub fn install_msi(msi_file: &str, log: &Logger, os: &str) -> Result<(), Box Result<(), Box> { +pub fn untargz(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), Error> { log.trace(format!( "Untargz {} to {}", compressed_file, @@ -331,18 +328,14 @@ pub fn untargz(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), let mut archive = Archive::new(tar); let parent_path = target .parent() - .ok_or(format!("Error getting parent of {:?}", file))?; + .ok_or(anyhow!(format!("Error getting parent of {:?}", file)))?; if !target.exists() { archive.unpack(parent_path)?; } Ok(()) } -pub fn uncompress_bz2( - compressed_file: &str, - target: &Path, - log: &Logger, -) -> Result<(), Box> { +pub fn uncompress_bz2(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), Error> { log.trace(format!( "Uncompress {} to {}", compressed_file, @@ -369,7 +362,7 @@ pub fn unzip( target: &Path, log: &Logger, single_file: Option, -) -> Result<(), Box> { +) -> Result<(), Error> { let file = File::open(compressed_file)?; let compressed_path = Path::new(compressed_file); let tmp_path = compressed_path @@ -435,11 +428,10 @@ pub fn unzip( } } if unzipped_files == 0 { - return Err(format!( + return Err(anyhow!(format!( "Problem uncompressing zip ({} files extracted)", unzipped_files - ) - .into()); + ))); } fs::remove_file(compressed_path)?; @@ -534,10 +526,10 @@ pub fn get_binary_extension(os: &str) -> &str { } } -pub fn parse_version(version_text: String, log: &Logger) -> Result> { +pub fn parse_version(version_text: String, log: &Logger) -> Result { if version_text.to_ascii_lowercase().contains("error") { log.debug(format!("Error parsing version: {}", version_text)); - return Err(PARSE_ERROR.into()); + return Err(anyhow!(PARSE_ERROR)); } let mut parsed_version = "".to_string(); let re_numbers_dots = Regex::new(r"[^\d^.]")?; @@ -561,7 +553,7 @@ pub fn path_to_string(path: &Path) -> String { .unwrap_or_default() } -pub fn read_bytes_from_file(file_path: &str) -> Result, Box> { +pub fn read_bytes_from_file(file_path: &str) -> Result, Error> { let file = File::open(file_path)?; let mut reader = BufReader::new(file); let mut buffer = Vec::new(); diff --git a/rust/src/firefox.rs b/rust/src/firefox.rs index bd701c098d0aa..f66c4dbb0efcf 100644 --- a/rust/src/firefox.rs +++ b/rust/src/firefox.rs @@ -17,9 +17,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::PathBuf; use crate::config::ARCH::{ARM64, X32}; @@ -71,7 +73,7 @@ pub struct FirefoxManager { } impl FirefoxManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = FIREFOX_NAME; let driver_name = GECKODRIVER_NAME; let config = ManagerConfig::default(browser_name, driver_name); @@ -90,10 +92,7 @@ impl FirefoxManager { format!("{}{}", FIREFOX_DETAILS_URL, endpoint) } - fn request_versions_from_online( - &mut self, - endpoint: &str, - ) -> Result, Box> { + fn request_versions_from_online(&mut self, endpoint: &str) -> Result, Error> { let browser_version = self.get_browser_version().to_string(); let firefox_versions_url = self.create_firefox_details_url(endpoint); let firefox_versions = @@ -172,7 +171,7 @@ impl SeleniumManager for FirefoxManager { ]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.general_discover_browser_version( r#"HKCU\Software\Mozilla\Mozilla Firefox"#, REG_CURRENT_VERSION_ARG, @@ -184,7 +183,7 @@ impl SeleniumManager for FirefoxManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { let major_browser_version_binding = self.get_major_browser_version(); let major_browser_version = major_browser_version_binding.as_str(); let cache_path = self.get_cache_path()?; @@ -225,11 +224,11 @@ impl SeleniumManager for FirefoxManager { } } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { self.general_request_browser_version(self.browser_name) } - fn get_driver_url(&mut self) -> Result> { + fn get_driver_url(&mut self) -> Result { let driver_version = self.get_driver_version(); let os = self.get_os(); let arch = self.get_arch(); @@ -267,7 +266,7 @@ impl SeleniumManager for FirefoxManager { )) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(compose_driver_path_in_cache( self.get_cache_path()?.unwrap_or_default(), self.driver_name, @@ -332,7 +331,7 @@ impl SeleniumManager for FirefoxManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { let browser_name = self.browser_name; self.get_logger().trace(format!( "Using Firefox endpoints to find out latest stable {} version", @@ -354,7 +353,7 @@ impl SeleniumManager for FirefoxManager { fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { let browser_name = self.browser_name; let browser_version = self.get_browser_version().to_string(); self.get_logger().trace(format!( @@ -387,13 +386,12 @@ impl SeleniumManager for FirefoxManager { let min_downloadable_version = self.get_min_browser_version_for_download()?; if major_browser_version < min_downloadable_version { - return Err(format_three_args( + return Err(anyhow!(format_three_args( UNAVAILABLE_DOWNLOAD_ERROR_MESSAGE, browser_name, &browser_version, &min_downloadable_version.to_string(), - ) - .into()); + ))); } let mut firefox_versions = @@ -419,7 +417,7 @@ impl SeleniumManager for FirefoxManager { } } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { let os = self.get_os(); let min_browser_version_for_download = if WINDOWS.is(os) { MIN_DOWNLOADABLE_FIREFOX_VERSION_WIN @@ -431,10 +429,7 @@ impl SeleniumManager for FirefoxManager { Ok(min_browser_version_for_download) } - fn get_browser_binary_path( - &mut self, - browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, browser_version: &str) -> Result { let browser_in_cache = self.get_browser_path_in_cache()?; if MACOS.is(self.get_os()) { let macos_app_name = if self.is_nightly(browser_version) { @@ -448,10 +443,7 @@ impl SeleniumManager for FirefoxManager { } } - fn get_browser_url_for_download( - &mut self, - browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result { let arch = self.get_arch(); let os = self.get_os(); let platform_label; @@ -522,10 +514,7 @@ impl SeleniumManager for FirefoxManager { } } - fn get_browser_label_for_download( - &self, - browser_version: &str, - ) -> Result, Box> { + fn get_browser_label_for_download(&self, browser_version: &str) -> Result, Error> { let browser_label = if self.is_nightly(browser_version) { FIREFOX_NIGHTLY_VOLUME } else { diff --git a/rust/src/grid.rs b/rust/src/grid.rs index e3855893cacb3..a96f0e8e87754 100644 --- a/rust/src/grid.rs +++ b/rust/src/grid.rs @@ -16,9 +16,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::PathBuf; use crate::files::BrowserPath; @@ -51,7 +53,7 @@ pub struct GridManager { } impl GridManager { - pub fn new(driver_version: String) -> Result, Box> { + pub fn new(driver_version: String) -> Result, Error> { let browser_name = GRID_NAME; let driver_name = GRID_RELEASE; let mut config = ManagerConfig::default(browser_name, driver_name); @@ -90,7 +92,7 @@ impl SeleniumManager for GridManager { HashMap::new() } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { Ok(None) } @@ -98,7 +100,7 @@ impl SeleniumManager for GridManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { let major_browser_version_binding = self.get_major_browser_version(); let major_browser_version = major_browser_version_binding.as_str(); let cache_path = self.get_cache_path()?; @@ -166,17 +168,20 @@ impl SeleniumManager for GridManager { Ok(driver_version) } else { - Err(format!("{} release not available", self.get_driver_name()).into()) + Err(anyhow!(format!( + "{} release not available", + self.get_driver_name() + ))) } } } } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { Ok(None) } - fn get_driver_url(&mut self) -> Result> { + fn get_driver_url(&mut self) -> Result { if self.driver_url.is_some() { return Ok(self.driver_url.as_ref().unwrap().to_string()); } @@ -192,7 +197,7 @@ impl SeleniumManager for GridManager { )) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { let browser_name = self.get_browser_name(); let driver_name = self.get_driver_name(); let driver_version = self.get_driver_version(); @@ -231,39 +236,33 @@ impl SeleniumManager for GridManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { self.unavailable_download() } - fn get_browser_binary_path( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } - fn get_browser_url_for_download( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } fn get_browser_label_for_download( &self, _browser_version: &str, - ) -> Result, Box> { + ) -> Result, Error> { self.unavailable_download() } } diff --git a/rust/src/iexplorer.rs b/rust/src/iexplorer.rs index a045cae3b1232..e94c4a370169c 100644 --- a/rust/src/iexplorer.rs +++ b/rust/src/iexplorer.rs @@ -16,9 +16,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::PathBuf; use crate::files::{compose_driver_path_in_cache, BrowserPath}; @@ -56,7 +58,7 @@ pub struct IExplorerManager { } impl IExplorerManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = IE_NAMES[0]; let driver_name = IEDRIVER_NAME; let mut config = ManagerConfig::default(browser_name, driver_name); @@ -98,7 +100,7 @@ impl SeleniumManager for IExplorerManager { )]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.general_discover_browser_version( r#"HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer"#, REG_VERSION_ARG, @@ -110,7 +112,7 @@ impl SeleniumManager for IExplorerManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { let major_browser_version_binding = self.get_major_browser_version(); let major_browser_version = major_browser_version_binding.as_str(); let cache_path = self.get_cache_path()?; @@ -174,17 +176,20 @@ impl SeleniumManager for IExplorerManager { Ok(driver_version) } else { - Err(format!("{} release not available", self.get_driver_name()).into()) + Err(anyhow!(format!( + "{} release not available", + self.get_driver_name() + ))) } } } } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { Ok(None) } - fn get_driver_url(&mut self) -> Result> { + fn get_driver_url(&mut self) -> Result { if self.driver_url.is_some() { return Ok(self.driver_url.as_ref().unwrap().to_string()); } @@ -199,7 +204,7 @@ impl SeleniumManager for IExplorerManager { )) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(compose_driver_path_in_cache( self.get_cache_path()?.unwrap_or_default(), self.driver_name, @@ -236,39 +241,33 @@ impl SeleniumManager for IExplorerManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { self.unavailable_download() } - fn get_browser_binary_path( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } - fn get_browser_url_for_download( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } fn get_browser_label_for_download( &self, _browser_version: &str, - ) -> Result, Box> { + ) -> Result, Error> { self.unavailable_download() } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index bbdb34d737e87..8ae44f6b8ef91 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -28,10 +28,12 @@ use std::{env, fs}; use crate::config::OS::{MACOS, WINDOWS}; use crate::config::{str_to_os, ManagerConfig}; +use anyhow::Error; use is_executable::IsExecutable; use reqwest::{Client, Proxy}; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::{Path, PathBuf}; use std::time::Duration; use walkdir::{DirEntry, WalkDir}; @@ -126,17 +128,17 @@ pub trait SeleniumManager { fn get_browser_path_map(&self) -> HashMap; - fn discover_browser_version(&mut self) -> Result, Box>; + fn discover_browser_version(&mut self) -> Result, Error>; fn get_driver_name(&self) -> &str; - fn request_driver_version(&mut self) -> Result>; + fn request_driver_version(&mut self) -> Result; - fn request_browser_version(&mut self) -> Result, Box>; + fn request_browser_version(&mut self) -> Result, Error>; - fn get_driver_url(&mut self) -> Result>; + fn get_driver_url(&mut self) -> Result; - fn get_driver_path_in_cache(&self) -> Result>; + fn get_driver_path_in_cache(&self) -> Result; fn get_config(&self) -> &ManagerConfig; @@ -153,33 +155,27 @@ pub trait SeleniumManager { fn request_latest_browser_version_from_online( &mut self, browser_version: &str, - ) -> Result>; + ) -> Result; fn request_fixed_browser_version_from_online( &mut self, browser_version: &str, - ) -> Result>; + ) -> Result; - fn get_min_browser_version_for_download(&self) -> Result>; + fn get_min_browser_version_for_download(&self) -> Result; - fn get_browser_binary_path(&mut self, browser_version: &str) - -> Result>; + fn get_browser_binary_path(&mut self, browser_version: &str) -> Result; - fn get_browser_url_for_download( - &mut self, - browser_version: &str, - ) -> Result>; + fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result; - fn get_browser_label_for_download( - &self, - _browser_version: &str, - ) -> Result, Box>; + fn get_browser_label_for_download(&self, _browser_version: &str) + -> Result, Error>; // ---------------------------------------------------------- // Shared functions // ---------------------------------------------------------- - fn download_driver(&mut self) -> Result<(), Box> { + fn download_driver(&mut self) -> Result<(), Error> { let driver_url = self.get_driver_url()?; self.get_logger().debug(format!( "Downloading {} {} from {}", @@ -209,13 +205,12 @@ pub trait SeleniumManager { } } - fn download_browser(&mut self) -> Result, Box> { + fn download_browser(&mut self) -> Result, Error> { if WINDOWS.is(self.get_os()) && self.is_edge() && !self.is_windows_admin() { - return Err(format_one_arg( + return Err(anyhow!(format_one_arg( NOT_ADMIN_FOR_EDGE_INSTALLER_ERR_MSG, self.get_browser_name(), - ) - .into()); + ))); } let browser_version; @@ -232,13 +227,12 @@ pub trait SeleniumManager { && !self.is_browser_version_empty() && major_browser_version_int < min_browser_version_for_download { - return Err(format_three_args( + return Err(anyhow!(format_three_args( UNAVAILABLE_DOWNLOAD_WITH_MIN_VERSION_ERR_MSG, self.get_browser_name(), &major_browser_version, &min_browser_version_for_download.to_string(), - ) - .into()); + ))); } // Browser version is checked in the local metadata @@ -429,7 +423,7 @@ pub trait SeleniumManager { fn discover_driver_version_and_download_browser_if_necessary( &mut self, - ) -> Result> { + ) -> Result { let mut download_browser = self.is_force_browser_download(); let major_browser_version = self.get_major_browser_version(); @@ -515,23 +509,21 @@ pub trait SeleniumManager { browser_path.unwrap().display() )); } else if !self.is_iexplorer() && !self.is_grid() && !self.is_safari() { - return Err(format!( + return Err(anyhow!(format!( "{}{} cannot be downloaded", self.get_browser_name(), self.get_browser_version_label() - ) - .into()); + ))); } } // Second, we request the driver version using online endpoints let driver_version = self.request_driver_version()?; if driver_version.is_empty() { - Err(format!( + Err(anyhow!(format!( "The {} version cannot be discovered", self.get_driver_name() - ) - .into()) + ))) } else { self.get_logger().debug(format!( "Required driver: {} {}", @@ -702,7 +694,7 @@ pub trait SeleniumManager { self.is_stable(self.get_browser_version()) } - fn setup(&mut self) -> Result> { + fn setup(&mut self) -> Result { let mut driver_in_path = None; let mut driver_in_path_version = None; @@ -824,7 +816,7 @@ pub trait SeleniumManager { self.is_driver(entry) && match_driver_version } - fn find_best_driver_from_cache(&self) -> Result, Box> { + fn find_best_driver_from_cache(&self) -> Result, Error> { let cache_path = self.get_cache_path()?.unwrap_or_default(); let drivers_in_cache_matching_version: Vec = WalkDir::new(&cache_path) .into_iter() @@ -858,15 +850,15 @@ pub trait SeleniumManager { } } - fn get_major_version(&self, full_version: &str) -> Result> { + fn get_major_version(&self, full_version: &str) -> Result { get_index_version(full_version, 0) } - fn get_minor_version(&self, full_version: &str) -> Result> { + fn get_minor_version(&self, full_version: &str) -> Result { get_index_version(full_version, 1) } - fn get_selenium_release_version(&self) -> Result> { + fn get_selenium_release_version(&self) -> Result { let driver_version = self.get_driver_version(); if driver_version.contains(SNAPSHOT) { return Ok(NIGHTLY.to_string()); @@ -880,16 +872,16 @@ pub trait SeleniumManager { self.get_driver_name(), driver_version ); - let index = release_version.rfind('.').ok_or(error_message)? + 1; + let index = release_version.rfind('.').ok_or(anyhow!(error_message))? + 1; release_version = release_version[..index].to_string(); release_version.push('0'); } Ok(format!("selenium-{release_version}")) } - fn assert_online_or_err(&self, message: &str) -> Result<(), Box> { + fn assert_online_or_err(&self, message: &str) -> Result<(), Error> { if self.is_offline() { - return Err(format_one_arg(message, self.get_driver_name()).into()); + return Err(anyhow!(format_one_arg(message, self.get_driver_name()))); } Ok(()) } @@ -913,7 +905,7 @@ pub trait SeleniumManager { fn general_request_browser_version( &mut self, browser_name: &str, - ) -> Result, Box> { + ) -> Result, Error> { let browser_version; let original_browser_version = self.get_config().browser_version.clone(); let major_browser_version = self.get_major_browser_version(); @@ -964,7 +956,7 @@ pub trait SeleniumManager { reg_key: &'static str, reg_version_arg: &'static str, cmd_version_arg: &str, - ) -> Result, Box> { + ) -> Result, Error> { let mut browser_path = self.get_browser_path().to_string(); let mut escaped_browser_path = self.get_escaped_path(browser_path.to_string()); if browser_path.is_empty() { @@ -1017,10 +1009,7 @@ pub trait SeleniumManager { Ok(self.detect_browser_version(commands)) } - fn discover_safari_version( - &mut self, - safari_path: String, - ) -> Result, Box> { + fn discover_safari_version(&mut self, safari_path: String) -> Result, Error> { let mut browser_path = self.get_browser_path().to_string(); let mut commands = Vec::new(); if browser_path.is_empty() { @@ -1041,7 +1030,7 @@ pub trait SeleniumManager { Ok(self.detect_browser_version(commands)) } - fn get_browser_path_in_cache(&self) -> Result> { + fn get_browser_path_in_cache(&self) -> Result { Ok(self .get_cache_path()? .unwrap_or_default() @@ -1059,21 +1048,21 @@ pub trait SeleniumManager { } } - fn unavailable_download(&self) -> Result> + fn unavailable_download(&self) -> Result where Self: Sized, { self.throw_error_message(UNAVAILABLE_DOWNLOAD_ERR_MSG) } - fn unavailable_discovery(&self) -> Result> + fn unavailable_discovery(&self) -> Result where Self: Sized, { self.throw_error_message(ONLINE_DISCOVERY_ERROR_MESSAGE) } - fn throw_error_message(&self, error_message: &str) -> Result> + fn throw_error_message(&self, error_message: &str) -> Result where Self: Sized, { @@ -1083,12 +1072,11 @@ pub trait SeleniumManager { } else { format!(" {}", browser_version) }; - Err(format_two_args( + Err(anyhow!(format_two_args( error_message, self.get_browser_name(), &browser_version_label, - ) - .into()) + ))) } // ---------------------------------------------------------- @@ -1212,7 +1200,7 @@ pub trait SeleniumManager { self.get_config().proxy.as_str() } - fn set_proxy(&mut self, proxy: String) -> Result<(), Box> { + fn set_proxy(&mut self, proxy: String) -> Result<(), Error> { if !proxy.is_empty() && !self.is_offline() { self.get_logger().debug(format!("Using proxy: {}", &proxy)); self.get_config_mut().proxy = proxy; @@ -1225,7 +1213,7 @@ pub trait SeleniumManager { self.get_config().timeout } - fn set_timeout(&mut self, timeout: u64) -> Result<(), Box> { + fn set_timeout(&mut self, timeout: u64) -> Result<(), Error> { if timeout != REQUEST_TIMEOUT_SEC { self.get_config_mut().timeout = timeout; self.get_logger() @@ -1235,7 +1223,7 @@ pub trait SeleniumManager { Ok(()) } - fn update_http_client(&mut self) -> Result<(), Box> { + fn update_http_client(&mut self) -> Result<(), Error> { let proxy = self.get_proxy(); let timeout = self.get_timeout(); let http_client = create_http_client(timeout, proxy)?; @@ -1283,7 +1271,7 @@ pub trait SeleniumManager { } } - fn get_cache_path(&self) -> Result, Box> { + fn get_cache_path(&self) -> Result, Error> { let path = Path::new(&self.get_config().cache_path); match create_path_if_not_exists(path) { Ok(_) => { @@ -1312,9 +1300,7 @@ pub trait SeleniumManager { // Public functions // ---------------------------------------------------------- -pub fn get_manager_by_browser( - browser_name: String, -) -> Result, Box> { +pub fn get_manager_by_browser(browser_name: String) -> Result, Error> { let browser_name_lower_case = browser_name.to_ascii_lowercase(); if browser_name_lower_case.eq(CHROME_NAME) { Ok(ChromeManager::new()?) @@ -1329,16 +1315,11 @@ pub fn get_manager_by_browser( } else if SAFARITP_NAMES.contains(&browser_name_lower_case.as_str()) { Ok(SafariTPManager::new()?) } else { - Err(Box::new(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - format!("Invalid browser name: {browser_name}"), - ))) + Err(anyhow!(format!("Invalid browser name: {browser_name}"))) } } -pub fn get_manager_by_driver( - driver_name: String, -) -> Result, Box> { +pub fn get_manager_by_driver(driver_name: String) -> Result, Error> { if driver_name.eq_ignore_ascii_case(CHROMEDRIVER_NAME) { Ok(ChromeManager::new()?) } else if driver_name.eq_ignore_ascii_case(GECKODRIVER_NAME) { @@ -1350,10 +1331,7 @@ pub fn get_manager_by_driver( } else if driver_name.eq_ignore_ascii_case(SAFARIDRIVER_NAME) { Ok(SafariManager::new()?) } else { - Err(Box::new(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - format!("Invalid driver name: {driver_name}"), - ))) + Err(anyhow!(format!("Invalid driver name: {driver_name}"))) } } @@ -1371,7 +1349,7 @@ pub fn clear_cache(log: &Logger, path: &str) { } } -pub fn create_http_client(timeout: u64, proxy: &str) -> Result> { +pub fn create_http_client(timeout: u64, proxy: &str) -> Result { let mut client_builder = Client::builder() .danger_accept_invalid_certs(true) .use_rustls_tls() @@ -1401,10 +1379,10 @@ pub fn format_three_args(string: &str, arg1: &str, arg2: &str, arg3: &str) -> St // Private functions // ---------------------------------------------------------- -fn get_index_version(full_version: &str, index: usize) -> Result> { +fn get_index_version(full_version: &str, index: usize) -> Result { let version_vec: Vec<&str> = full_version.split('.').collect(); Ok(version_vec .get(index) - .ok_or(format!("Wrong version: {}", full_version))? + .ok_or(anyhow!(format!("Wrong version: {}", full_version)))? .to_string()) } diff --git a/rust/src/main.rs b/rust/src/main.rs index 2fd4b2a837b14..d92de21a6c7da 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -15,9 +15,11 @@ // specific language governing permissions and limitations // under the License. +use std::backtrace::{Backtrace, BacktraceStatus}; use std::path::Path; use std::process::exit; +use anyhow::Error; use clap::Parser; use exitcode::DATAERR; @@ -146,22 +148,22 @@ fn main() { let mut selenium_manager: Box = if !browser_name.is_empty() { get_manager_by_browser(browser_name).unwrap_or_else(|err| { - log.error(err); - flush_and_exit(DATAERR, &log); + log.error(&err); + flush_and_exit(DATAERR, &log, Some(err)); }) } else if !driver_name.is_empty() { get_manager_by_driver(driver_name).unwrap_or_else(|err| { - log.error(err); - flush_and_exit(DATAERR, &log); + log.error(&err); + flush_and_exit(DATAERR, &log, Some(err)); }) } else if grid.is_some() { GridManager::new(grid.as_ref().unwrap().to_string()).unwrap_or_else(|err| { - log.error(err); - flush_and_exit(DATAERR, &log); + log.error(&err); + flush_and_exit(DATAERR, &log, Some(err)); }) } else { log.error("You need to specify a browser or driver"); - flush_and_exit(DATAERR, &log); + flush_and_exit(DATAERR, &log, None); }; if cli.offline { @@ -202,7 +204,7 @@ fn main() { .map(|driver_path| { let log = selenium_manager.get_logger(); log_driver_and_browser_path(log, &driver_path, selenium_manager.get_browser_path()); - flush_and_exit(OK, log); + flush_and_exit(OK, log, None); }) .unwrap_or_else(|err| { let log = selenium_manager.get_logger(); @@ -219,13 +221,13 @@ fn main() { &best_driver_from_cache, selenium_manager.get_browser_path(), ); - flush_and_exit(OK, log); + flush_and_exit(OK, log, Some(err)); } else if selenium_manager.is_offline() { log.warn(err.to_string()); - flush_and_exit(OK, log); + flush_and_exit(OK, log, Some(err)); } else { log.error(err.to_string()); - flush_and_exit(DATAERR, log); + flush_and_exit(DATAERR, log, Some(err)); } }); } @@ -235,14 +237,21 @@ fn log_driver_and_browser_path(log: &Logger, driver_path: &Path, browser_path: & log.info(format!("{}{}", DRIVER_PATH, driver_path.display())); } else { log.error(format!("Driver unavailable: {}", DRIVER_PATH)); - flush_and_exit(UNAVAILABLE, log); + flush_and_exit(UNAVAILABLE, log, None); } if !browser_path.is_empty() { log.info(format!("{}{}", BROWSER_PATH, browser_path)); } } -fn flush_and_exit(code: i32, log: &Logger) -> ! { +fn flush_and_exit(code: i32, log: &Logger, err: Option) -> ! { + if let Some(error) = err { + let backtrace = Backtrace::capture(); + let backtrace_status = backtrace.status(); + if backtrace_status == BacktraceStatus::Captured { + log.debug(format!("Backtrace:\n{}", error.backtrace())); + } + } log.set_code(code); log.flush(); exit(code); diff --git a/rust/src/safari.rs b/rust/src/safari.rs index 1a6ae66c4d4df..fe65fdad5e122 100644 --- a/rust/src/safari.rs +++ b/rust/src/safari.rs @@ -16,9 +16,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::PathBuf; use std::string::ToString; @@ -41,7 +43,7 @@ pub struct SafariManager { } impl SafariManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = SAFARI_NAME; let driver_name = SAFARIDRIVER_NAME; let config = ManagerConfig::default(browser_name, driver_name); @@ -78,7 +80,7 @@ impl SeleniumManager for SafariManager { HashMap::from([(BrowserPath::new(MACOS, STABLE), SAFARI_PATH)]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.discover_safari_version(SAFARI_FULL_PATH.to_string()) } @@ -86,19 +88,22 @@ impl SeleniumManager for SafariManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { Ok("(local)".to_string()) } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { Ok(None) } - fn get_driver_url(&mut self) -> Result> { - Err(format!("{} not available for download", self.get_driver_name()).into()) + fn get_driver_url(&mut self) -> Result { + Err(anyhow!(format!( + "{} not available for download", + self.get_driver_name() + ))) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(PathBuf::from("/usr/bin/safaridriver")) } @@ -129,39 +134,33 @@ impl SeleniumManager for SafariManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { self.unavailable_download() } - fn get_browser_binary_path( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } - fn get_browser_url_for_download( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } fn get_browser_label_for_download( &self, _browser_version: &str, - ) -> Result, Box> { + ) -> Result, Error> { self.unavailable_download() } } diff --git a/rust/src/safaritp.rs b/rust/src/safaritp.rs index 4ce0ccc617b68..4837a4a822309 100644 --- a/rust/src/safaritp.rs +++ b/rust/src/safaritp.rs @@ -16,9 +16,11 @@ // under the License. use crate::config::ManagerConfig; +use anyhow::Error; use reqwest::Client; use std::collections::HashMap; -use std::error::Error; + +use anyhow::anyhow; use std::path::PathBuf; use std::string::ToString; @@ -47,7 +49,7 @@ pub struct SafariTPManager { } impl SafariTPManager { - pub fn new() -> Result, Box> { + pub fn new() -> Result, Error> { let browser_name = SAFARITP_NAMES[0]; let driver_name = SAFARITPDRIVER_NAME; let config = ManagerConfig::default(browser_name, driver_name); @@ -84,7 +86,7 @@ impl SeleniumManager for SafariTPManager { HashMap::from([(BrowserPath::new(MACOS, STABLE), SAFARITP_PATH)]) } - fn discover_browser_version(&mut self) -> Result, Box> { + fn discover_browser_version(&mut self) -> Result, Error> { self.discover_safari_version(SAFARITP_FULL_PATH.to_string()) } @@ -92,19 +94,22 @@ impl SeleniumManager for SafariTPManager { self.driver_name } - fn request_driver_version(&mut self) -> Result> { + fn request_driver_version(&mut self) -> Result { Ok("(local)".to_string()) } - fn request_browser_version(&mut self) -> Result, Box> { + fn request_browser_version(&mut self) -> Result, Error> { Ok(None) } - fn get_driver_url(&mut self) -> Result> { - Err(format!("{} not available for download", self.get_driver_name()).into()) + fn get_driver_url(&mut self) -> Result { + Err(anyhow!(format!( + "{} not available for download", + self.get_driver_name() + ))) } - fn get_driver_path_in_cache(&self) -> Result> { + fn get_driver_path_in_cache(&self) -> Result { Ok(PathBuf::from( "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver", )) @@ -137,39 +142,33 @@ impl SeleniumManager for SafariTPManager { fn request_latest_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } fn request_fixed_browser_version_from_online( &mut self, _browser_version: &str, - ) -> Result> { + ) -> Result { self.unavailable_download() } - fn get_min_browser_version_for_download(&self) -> Result> { + fn get_min_browser_version_for_download(&self) -> Result { self.unavailable_download() } - fn get_browser_binary_path( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } - fn get_browser_url_for_download( - &mut self, - _browser_version: &str, - ) -> Result> { + fn get_browser_url_for_download(&mut self, _browser_version: &str) -> Result { self.unavailable_download() } fn get_browser_label_for_download( &self, _browser_version: &str, - ) -> Result, Box> { + ) -> Result, Error> { self.unavailable_download() } } diff --git a/rust/src/shell.rs b/rust/src/shell.rs index d81b0efbaf8d3..1c50d88cb77e3 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -16,7 +16,7 @@ // under the License. use crate::{Logger, WINDOWS}; -use std::error::Error; +use anyhow::Error; pub const CRLF: &str = "\r\n"; pub const LF: &str = "\n"; @@ -68,14 +68,14 @@ pub fn run_shell_command_with_log( log: &Logger, os: &str, command: Command, -) -> Result> { +) -> Result { log.debug(format!("Running command: {}", command.display())); let output = run_shell_command_by_os(os, command)?; log.debug(format!("Output: {:?}", output)); Ok(output) } -pub fn run_shell_command_by_os(os: &str, command: Command) -> Result> { +pub fn run_shell_command_by_os(os: &str, command: Command) -> Result { let (shell, flag) = if WINDOWS.is(os) { ("cmd", "/c") } else { @@ -84,11 +84,7 @@ pub fn run_shell_command_by_os(os: &str, command: Command) -> Result Result> { +pub fn run_shell_command(shell: &str, flag: &str, command: Command) -> Result { let mut process = std::process::Command::new(shell); process.arg(flag); diff --git a/rust/tests/browser_tests.rs b/rust/tests/browser_tests.rs index 14818e892c519..8d1783df23e71 100644 --- a/rust/tests/browser_tests.rs +++ b/rust/tests/browser_tests.rs @@ -85,7 +85,7 @@ fn wrong_parameters_test( .assert() .try_success(); - assert_output(&mut cmd, result, "in PATH", error_code); + assert_output(&mut cmd, result, vec!["in PATH"], error_code); } #[rstest] diff --git a/rust/tests/common.rs b/rust/tests/common.rs index 3db8572bdf93c..59eedc700ae0b 100644 --- a/rust/tests/common.rs +++ b/rust/tests/common.rs @@ -78,13 +78,15 @@ pub fn display_output(cmd: &mut Command) { pub fn assert_output( cmd: &mut Command, assert_result: AssertResult, - expected_output: &str, + expected_output: Vec<&str>, error_code: i32, ) { if assert_result.is_ok() { let stdout = &cmd.unwrap().stdout; let output = std::str::from_utf8(stdout).unwrap(); - assert!(output.contains(expected_output)); + expected_output + .iter() + .for_each(|o| assert!(output.contains(o))); } else { assert!(assert_result .err() diff --git a/rust/tests/grid_tests.rs b/rust/tests/grid_tests.rs index 3f5f4958f7ea8..632ef4e52a2f4 100644 --- a/rust/tests/grid_tests.rs +++ b/rust/tests/grid_tests.rs @@ -78,5 +78,5 @@ fn grid_error_test(#[case] grid_version: &str) { let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager")); let result = cmd.args(["--grid", grid_version]).assert().try_success(); - assert_output(&mut cmd, result, "There was an error", DATAERR); + assert_output(&mut cmd, result, vec!["There was an error"], DATAERR); } diff --git a/rust/tests/proxy_tests.rs b/rust/tests/proxy_tests.rs index 51d4b08fe0220..3f9c15f3804c7 100644 --- a/rust/tests/proxy_tests.rs +++ b/rust/tests/proxy_tests.rs @@ -35,7 +35,7 @@ async fn wrong_proxy_test() { .assert() .try_success(); - assert_output(&mut cmd, result, "in PATH", DATAERR); + assert_output(&mut cmd, result, vec!["in PATH"], DATAERR); } #[test] fn wrong_protocol_proxy_test() { @@ -45,7 +45,7 @@ fn wrong_protocol_proxy_test() { .assert() .try_success(); - assert_output(&mut cmd, result, "There was an error", DATAERR); + assert_output(&mut cmd, result, vec!["There was an error"], DATAERR); } #[test] @@ -61,5 +61,5 @@ fn wrong_port_proxy_test() { .assert() .try_success(); - assert_output(&mut cmd, result, "There was an error", DATAERR); + assert_output(&mut cmd, result, vec!["There was an error"], DATAERR); }