Skip to content

Commit

Permalink
[rust] Allow Selenium Manager to be used as a Rust lib crate (Seleniu…
Browse files Browse the repository at this point in the history
  • Loading branch information
bonigarcia committed Dec 9, 2022
1 parent 6399429 commit 65e3eb6
Show file tree
Hide file tree
Showing 10 changed files with 661 additions and 487 deletions.
8 changes: 8 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
name = "selenium-manager"
version = "1.0.0-M2"
edition = "2021"
authors = ["Selenium <selenium-developers@googlegroups.com"]
license = "Apache-2.0"
homepage = "https://www.selenium.dev/"
repository = "https://github.com/SeleniumHQ/selenium"
documentation = "https://www.selenium.dev/documentation/"
description = """
Selenium Manager is a CLI tool that automatically manages the browser/driver infrastructure required by Selenium.
"""

[dependencies]
clap = { version = "4.0.22", features = ["derive"] }
Expand Down
101 changes: 55 additions & 46 deletions rust/src/chrome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@
// specific language governing permissions and limitations
// under the License.

use crate::config::ManagerConfig;
use std::collections::HashMap;
use std::error::Error;
use std::path::PathBuf;

use crate::config::ARCH::ARM64;
use crate::config::OS::{LINUX, MACOS, WINDOWS};
use crate::downloads::read_content_from_link;
use crate::files::compose_driver_path_in_cache;
use crate::is_unstable;
use crate::manager::ARCH::ARM64;
use crate::manager::OS::{LINUX, MACOS, WINDOWS};
use crate::manager::{
detect_browser_version, format_one_arg, format_two_args, get_major_version, BrowserManager,
BrowserPath, BETA, DASH_DASH_VERSION, DEV, ENV_LOCALAPPDATA, ENV_PROGRAM_FILES,
ENV_PROGRAM_FILES_X86, NIGHTLY, REG_QUERY, STABLE, WMIC_COMMAND,
};
use crate::files::{compose_driver_path_in_cache, BrowserPath};
use crate::metadata::{
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
};
use crate::{
SeleniumManager, BETA, DASH_DASH_VERSION, DEV, ENV_LOCALAPPDATA, ENV_PROGRAM_FILES,
ENV_PROGRAM_FILES_X86, NIGHTLY, REG_QUERY, STABLE, WMIC_COMMAND,
};

const BROWSER_NAME: &str = "chrome";
const DRIVER_NAME: &str = "chromedriver";
Expand All @@ -41,18 +40,20 @@ const LATEST_RELEASE: &str = "LATEST_RELEASE";
pub struct ChromeManager {
pub browser_name: &'static str,
pub driver_name: &'static str,
pub config: ManagerConfig,
}

impl ChromeManager {
pub fn new() -> Box<Self> {
Box::new(ChromeManager {
browser_name: BROWSER_NAME,
driver_name: DRIVER_NAME,
config: ManagerConfig::default(),
})
}
}

impl BrowserManager for ChromeManager {
impl SeleniumManager for ChromeManager {
fn get_browser_name(&self) -> &str {
self.browser_name
}
Expand Down Expand Up @@ -97,30 +98,31 @@ impl BrowserManager for ChromeManager {
])
}

fn get_browser_version(&self, os: &str, browser_version: &str) -> Option<String> {
match self.get_browser_path(os, browser_version) {
fn discover_browser_version(&self) -> Option<String> {
match self.get_browser_path() {
Some(browser_path) => {
let (shell, flag, args) = if WINDOWS.is(os) {
let mut commands = vec![
format_two_args(WMIC_COMMAND, ENV_PROGRAM_FILES, browser_path),
format_two_args(WMIC_COMMAND, ENV_PROGRAM_FILES_X86, browser_path),
format_two_args(WMIC_COMMAND, ENV_LOCALAPPDATA, browser_path),
];
if !is_unstable(browser_version) {
commands.push(format_one_arg(
REG_QUERY,
r#"HKCU\Software\Google\Chrome\BLBeacon"#,
));
}
("cmd", "/C", commands)
} else {
(
"sh",
"-c",
vec![format_one_arg(DASH_DASH_VERSION, browser_path)],
)
};
detect_browser_version(self.browser_name, shell, flag, args)
let (shell, flag, args) =
if WINDOWS.is(self.get_os()) {
let mut commands = vec![
self.format_two_args(WMIC_COMMAND, ENV_PROGRAM_FILES, browser_path),
self.format_two_args(WMIC_COMMAND, ENV_PROGRAM_FILES_X86, browser_path),
self.format_two_args(WMIC_COMMAND, ENV_LOCALAPPDATA, browser_path),
];
if !self.is_browser_version_unstable() {
commands.push(self.format_one_arg(
REG_QUERY,
r#"HKCU\Software\Google\Chrome\BLBeacon"#,
));
}
("cmd", "/C", commands)
} else {
(
"sh",
"-c",
vec![self.format_one_arg(DASH_DASH_VERSION, browser_path)],
)
};
self.detect_browser_version(shell, flag, args)
}
_ => None,
}
Expand All @@ -130,11 +132,8 @@ impl BrowserManager for ChromeManager {
self.driver_name
}

fn get_driver_version(
&self,
browser_version: &str,
_os: &str,
) -> Result<String, Box<dyn Error>> {
fn request_driver_version(&self) -> Result<String, Box<dyn Error>> {
let browser_version = self.get_browser_version();
let mut metadata = get_metadata();

match get_driver_version_from_metadata(&metadata.drivers, self.driver_name, browser_version)
Expand Down Expand Up @@ -168,19 +167,18 @@ impl BrowserManager for ChromeManager {
}
}

fn get_driver_url(
&self,
driver_version: &str,
os: &str,
arch: &str,
) -> Result<String, Box<dyn Error>> {
fn get_driver_url(&self) -> Result<String, Box<dyn Error>> {
let driver_version = self.get_driver_version();
let os = self.get_os();
let arch = self.get_arch();
let driver_label = if WINDOWS.is(os) {
"win32"
} else if MACOS.is(os) {
if ARM64.is(arch) {
// As of chromedriver 106, the naming convention for macOS ARM64 releases changed. See:
// https://groups.google.com/g/chromedriver-users/c/JRuQzH3qr2c
let major_driver_version = get_major_version(driver_version)?
let major_driver_version = self
.get_major_version(driver_version)?
.parse::<i32>()
.unwrap_or_default();
if major_driver_version < 106 {
Expand All @@ -200,7 +198,10 @@ impl BrowserManager for ChromeManager {
))
}

fn get_driver_path_in_cache(&self, driver_version: &str, os: &str, arch: &str) -> PathBuf {
fn get_driver_path_in_cache(&self) -> PathBuf {
let driver_version = self.get_driver_version();
let os = self.get_os();
let arch = self.get_arch();
let arch_folder = if WINDOWS.is(os) {
"win32"
} else if MACOS.is(os) {
Expand All @@ -214,4 +215,12 @@ impl BrowserManager for ChromeManager {
};
compose_driver_path_in_cache(self.driver_name, os, arch_folder, driver_version)
}

fn get_config(&self) -> &ManagerConfig {
&self.config
}

fn set_config(&mut self, config: ManagerConfig) {
self.config = config;
}
}
102 changes: 102 additions & 0 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::config::OS::{LINUX, MACOS, WINDOWS};
use std::env::consts::{ARCH, OS};

pub struct ManagerConfig {
pub browser_version: String,
pub driver_version: String,
pub os: String,
pub arch: String,
}

impl ManagerConfig {
pub fn default() -> ManagerConfig {
ManagerConfig {
browser_version: "".to_string(),
driver_version: "".to_string(),
os: OS.to_string(),
arch: ARCH.to_string(),
}
}

#[allow(clippy::should_implement_trait)]
pub fn clone(config: &ManagerConfig) -> ManagerConfig {
ManagerConfig {
browser_version: config.browser_version.as_str().to_string(),
driver_version: config.driver_version.as_str().to_string(),
os: config.os.as_str().to_string(),
arch: config.arch.as_str().to_string(),
}
}
}

#[allow(dead_code)]
#[allow(clippy::upper_case_acronyms)]
#[derive(Hash, Eq, PartialEq, Debug)]
pub enum OS {
WINDOWS,
MACOS,
LINUX,
}

impl OS {
pub fn to_str(&self) -> &str {
match self {
WINDOWS => "windows",
MACOS => "macos",
LINUX => "linux",
}
}

pub fn is(&self, os: &str) -> bool {
self.to_str().eq_ignore_ascii_case(os)
}
}

pub fn str_to_os(os: &str) -> OS {
if WINDOWS.is(os) {
WINDOWS
} else if MACOS.is(os) {
MACOS
} else {
LINUX
}
}

#[allow(dead_code)]
#[allow(clippy::upper_case_acronyms)]
pub enum ARCH {
X32,
X64,
ARM64,
}

impl ARCH {
pub fn to_str(&self) -> &str {
match self {
ARCH::X32 => "x86",
ARCH::X64 => "x86_64",
ARCH::ARM64 => "aarch64",
}
}

pub fn is(&self, arch: &str) -> bool {
self.to_str().eq_ignore_ascii_case(arch)
}
}
Loading

0 comments on commit 65e3eb6

Please sign in to comment.