Skip to content

Commit eafd7cf

Browse files
authored
[rust] Search better driver possible in the cache (#12753)
* [rust] Search better driver possible in the cache * [rust] Update Cargo.Bazel.lock
1 parent 8101236 commit eafd7cf

File tree

9 files changed

+266
-54
lines changed

9 files changed

+266
-54
lines changed

rust/Cargo.Bazel.lock

+92-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"checksum": "0c722a74f5cadc8bb75a62763e298e0698afcb48a51d9f7bf6754e285caa644b",
2+
"checksum": "1f16f4cfa433faeb0bd8242b382da4d71e41405dc8a07363d8c1f410ee0d651e",
33
"crates": {
44
"addr2line 0.19.0": {
55
"name": "addr2line",
@@ -7636,6 +7636,47 @@
76367636
},
76377637
"license": "Apache-2.0 OR BSL-1.0"
76387638
},
7639+
"same-file 1.0.6": {
7640+
"name": "same-file",
7641+
"version": "1.0.6",
7642+
"repository": {
7643+
"Http": {
7644+
"url": "https://crates.io/api/v1/crates/same-file/1.0.6/download",
7645+
"sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
7646+
}
7647+
},
7648+
"targets": [
7649+
{
7650+
"Library": {
7651+
"crate_name": "same_file",
7652+
"crate_root": "src/lib.rs",
7653+
"srcs": [
7654+
"**/*.rs"
7655+
]
7656+
}
7657+
}
7658+
],
7659+
"library_target_name": "same_file",
7660+
"common_attrs": {
7661+
"compile_data_glob": [
7662+
"**"
7663+
],
7664+
"deps": {
7665+
"common": [],
7666+
"selects": {
7667+
"cfg(windows)": [
7668+
{
7669+
"id": "winapi-util 0.1.5",
7670+
"target": "winapi_util"
7671+
}
7672+
]
7673+
}
7674+
},
7675+
"edition": "2018",
7676+
"version": "1.0.6"
7677+
},
7678+
"license": "Unlicense/MIT"
7679+
},
76397680
"sct 0.7.0": {
76407681
"name": "sct",
76417682
"version": "0.7.0",
@@ -7773,6 +7814,10 @@
77737814
"id": "toml 0.7.6",
77747815
"target": "toml"
77757816
},
7817+
{
7818+
"id": "walkdir 2.4.0",
7819+
"target": "walkdir"
7820+
},
77767821
{
77777822
"id": "zip 0.6.6",
77787823
"target": "zip"
@@ -10300,6 +10345,52 @@
1030010345
},
1030110346
"license": "MIT/Apache-2.0"
1030210347
},
10348+
"walkdir 2.4.0": {
10349+
"name": "walkdir",
10350+
"version": "2.4.0",
10351+
"repository": {
10352+
"Http": {
10353+
"url": "https://crates.io/api/v1/crates/walkdir/2.4.0/download",
10354+
"sha256": "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
10355+
}
10356+
},
10357+
"targets": [
10358+
{
10359+
"Library": {
10360+
"crate_name": "walkdir",
10361+
"crate_root": "src/lib.rs",
10362+
"srcs": [
10363+
"**/*.rs"
10364+
]
10365+
}
10366+
}
10367+
],
10368+
"library_target_name": "walkdir",
10369+
"common_attrs": {
10370+
"compile_data_glob": [
10371+
"**"
10372+
],
10373+
"deps": {
10374+
"common": [
10375+
{
10376+
"id": "same-file 1.0.6",
10377+
"target": "same_file"
10378+
}
10379+
],
10380+
"selects": {
10381+
"cfg(windows)": [
10382+
{
10383+
"id": "winapi-util 0.1.5",
10384+
"target": "winapi_util"
10385+
}
10386+
]
10387+
}
10388+
},
10389+
"edition": "2018",
10390+
"version": "2.4.0"
10391+
},
10392+
"license": "Unlicense/MIT"
10393+
},
1030310394
"want 0.3.0": {
1030410395
"name": "want",
1030510396
"version": "0.3.0",

rust/Cargo.lock

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ is_executable = "1.0.1"
3131
toml = "0.7.6"
3232
bzip2 = "0.4.4"
3333
sevenz-rust = "0.5.2"
34+
walkdir = "2.4.0"
3435

3536
[dev-dependencies]
3637
assert_cmd = "2.0.12"

rust/src/lib.rs

+69
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use std::collections::HashMap;
3434
use std::error::Error;
3535
use std::path::{Path, PathBuf};
3636
use std::time::Duration;
37+
use walkdir::{DirEntry, WalkDir};
3738

3839
use crate::downloads::download_to_tmp_folder;
3940
use crate::files::{parse_version, uncompress, BrowserPath};
@@ -593,6 +594,74 @@ pub trait SeleniumManager {
593594
Ok(driver_path)
594595
}
595596

597+
fn is_driver(&self, entry: &DirEntry) -> bool {
598+
let is_file = entry.path().is_file();
599+
600+
let is_driver = entry
601+
.file_name()
602+
.to_str()
603+
.map(|s| s.contains(&self.get_driver_name_with_extension()))
604+
.unwrap_or(false);
605+
606+
let match_os = entry
607+
.path()
608+
.to_str()
609+
.map(|s| s.contains(self.get_platform_label()))
610+
.unwrap_or(false);
611+
612+
is_file && is_driver && match_os
613+
}
614+
615+
fn is_driver_and_matches_browser_version(&self, entry: &DirEntry) -> bool {
616+
let match_driver_version = entry
617+
.path()
618+
.parent()
619+
.unwrap_or(entry.path())
620+
.file_name()
621+
.map(|s| {
622+
s.to_str()
623+
.unwrap_or_default()
624+
.starts_with(&self.get_major_browser_version())
625+
})
626+
.unwrap_or(false);
627+
628+
self.is_driver(entry) && match_driver_version
629+
}
630+
631+
fn find_best_driver_from_cache(&self) -> Result<Option<PathBuf>, Box<dyn Error>> {
632+
let cache_path = self.get_cache_path()?;
633+
let drivers_in_cache_matching_version: Vec<PathBuf> = WalkDir::new(&cache_path)
634+
.into_iter()
635+
.filter_map(|entry| entry.ok())
636+
.filter(|entry| self.is_driver_and_matches_browser_version(entry))
637+
.map(|entry| entry.path().to_owned())
638+
.collect();
639+
640+
// First we look for drivers in cache that matches browser version (should work for Chrome and Edge)
641+
if !drivers_in_cache_matching_version.is_empty() {
642+
Ok(Some(
643+
drivers_in_cache_matching_version
644+
.iter()
645+
.last()
646+
.unwrap()
647+
.to_owned(),
648+
))
649+
} else {
650+
// If not available, we look for the latest available driver in the cache
651+
let drivers_in_cache: Vec<PathBuf> = WalkDir::new(&cache_path)
652+
.into_iter()
653+
.filter_map(|entry| entry.ok())
654+
.filter(|entry| self.is_driver(entry))
655+
.map(|entry| entry.path().to_owned())
656+
.collect();
657+
if !drivers_in_cache.is_empty() {
658+
Ok(Some(drivers_in_cache.iter().last().unwrap().to_owned()))
659+
} else {
660+
Ok(None)
661+
}
662+
}
663+
}
664+
596665
fn get_major_version(&self, full_version: &str) -> Result<String, Box<dyn Error>> {
597666
get_index_version(full_version, 0)
598667
}

rust/src/main.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
use std::path::PathBuf;
1819
use std::process::exit;
1920

2021
use clap::Parser;
@@ -194,21 +195,26 @@ fn main() {
194195
.and_then(|_| selenium_manager.setup())
195196
.map(|driver_path| {
196197
let log = selenium_manager.get_logger();
197-
if driver_path.exists() {
198-
log.info(format!("{}{}", DRIVER_PATH, driver_path.display()));
199-
} else {
200-
log.error(format!("Driver unavailable: {}", DRIVER_PATH));
201-
flush_and_exit(UNAVAILABLE, log);
202-
}
203-
let browser_path = selenium_manager.get_browser_path();
204-
if !browser_path.is_empty() {
205-
log.info(format!("{}{}", BROWSER_PATH, browser_path));
206-
}
198+
log_driver_and_browser_path(log, &driver_path, selenium_manager.get_browser_path());
207199
flush_and_exit(OK, log);
208200
})
209201
.unwrap_or_else(|err| {
210202
let log = selenium_manager.get_logger();
211-
if selenium_manager.is_offline() {
203+
if let Some(best_driver_from_cache) =
204+
selenium_manager.find_best_driver_from_cache().unwrap()
205+
{
206+
log.warn(format!(
207+
"There was an error managing {} ({}); using driver found in the cache",
208+
selenium_manager.get_browser_name(),
209+
err
210+
));
211+
log_driver_and_browser_path(
212+
log,
213+
&best_driver_from_cache,
214+
selenium_manager.get_browser_path(),
215+
);
216+
flush_and_exit(OK, log);
217+
} else if selenium_manager.is_offline() {
212218
log.warn(err.to_string());
213219
flush_and_exit(OK, log);
214220
} else {
@@ -218,6 +224,18 @@ fn main() {
218224
});
219225
}
220226

227+
fn log_driver_and_browser_path(log: &Logger, driver_path: &PathBuf, browser_path: &str) {
228+
if driver_path.exists() {
229+
log.info(format!("{}{}", DRIVER_PATH, driver_path.display()));
230+
} else {
231+
log.error(format!("Driver unavailable: {}", DRIVER_PATH));
232+
flush_and_exit(UNAVAILABLE, log);
233+
}
234+
if !browser_path.is_empty() {
235+
log.info(format!("{}{}", BROWSER_PATH, browser_path));
236+
}
237+
}
238+
221239
fn flush_and_exit(code: i32, log: &Logger) -> ! {
222240
log.set_code(code);
223241
log.flush();

rust/tests/browser_tests.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ use assert_cmd::Command;
1919
use rstest::rstest;
2020
use std::env::consts::OS;
2121

22+
use crate::common::assert_output;
23+
24+
mod common;
25+
2226
#[rstest]
2327
#[case("chrome", "chromedriver", "114", "114.0.5735.90")]
2428
#[case("chrome", "chromedriver", "115", "115.0.5790")]
@@ -68,7 +72,7 @@ fn wrong_parameters_test(
6872
#[case] error_code: i32,
6973
) {
7074
let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager"));
71-
let assert_result = cmd
75+
let result = cmd
7276
.args([
7377
"--debug",
7478
"--browser",
@@ -81,17 +85,7 @@ fn wrong_parameters_test(
8185
.assert()
8286
.try_success();
8387

84-
if assert_result.is_ok() {
85-
let stdout = &cmd.unwrap().stdout;
86-
let output = std::str::from_utf8(stdout).unwrap();
87-
assert!(output.contains("in PATH"));
88-
} else {
89-
assert!(assert_result
90-
.err()
91-
.unwrap()
92-
.to_string()
93-
.contains(&error_code.to_string()));
94-
}
88+
assert_output(&mut cmd, result, "in PATH", error_code);
9589
}
9690

9791
#[rstest]

rust/tests/common.rs

+21
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
use assert_cmd::assert::AssertResult;
1819
use assert_cmd::Command;
1920
use std::borrow::BorrowMut;
2021
use std::env::consts::OS;
@@ -72,3 +73,23 @@ pub fn display_output(cmd: &mut Command) {
7273
let output = std::str::from_utf8(stdout).unwrap();
7374
println!("{}", output);
7475
}
76+
77+
#[allow(dead_code)]
78+
pub fn assert_output(
79+
cmd: &mut Command,
80+
assert_result: AssertResult,
81+
expected_output: &str,
82+
error_code: i32,
83+
) {
84+
if assert_result.is_ok() {
85+
let stdout = &cmd.unwrap().stdout;
86+
let output = std::str::from_utf8(stdout).unwrap();
87+
assert!(output.contains(expected_output));
88+
} else {
89+
assert!(assert_result
90+
.err()
91+
.unwrap()
92+
.to_string()
93+
.contains(&error_code.to_string()));
94+
}
95+
}

0 commit comments

Comments
 (0)