blob: f30243e18642671be95e23dfd36e3f395867ed68 [file] [edit]
// 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 std::error::Error;
use std::fs;
use std::fs::File;
use std::io;
use std::path::MAIN_SEPARATOR;
use std::path::{Path, PathBuf};
use crate::config::OS;
use directories::BaseDirs;
use flate2::read::GzDecoder;
use regex::Regex;
use tar::Archive;
use zip::ZipArchive;
use crate::config::OS::WINDOWS;
const CACHE_FOLDER: &str = ".cache/selenium";
const ZIP: &str = "zip";
const GZ: &str = "gz";
const XML: &str = "xml";
#[derive(Hash, Eq, PartialEq, Debug)]
pub struct BrowserPath {
os: OS,
channel: String,
}
impl BrowserPath {
pub fn new(os: OS, channel: &str) -> BrowserPath {
BrowserPath {
os,
channel: channel.to_string(),
}
}
}
pub fn create_path_if_not_exists(path: &Path) {
if !path.exists() {
fs::create_dir_all(&path).unwrap();
}
}
pub fn uncompress(compressed_file: &String, target: PathBuf) -> Result<(), Box<dyn Error>> {
let file = File::open(compressed_file)?;
let kind = infer::get_from_path(compressed_file)?
.ok_or(format!("Format for file {:?} cannot be inferred", file))?;
let extension = kind.extension();
log::trace!(
"The detected extension of the compressed file is {}",
extension
);
if extension.eq_ignore_ascii_case(ZIP) {
unzip(file, target)?
} else if extension.eq_ignore_ascii_case(GZ) {
untargz(file, target)?
} else if extension.eq_ignore_ascii_case(XML) {
return Err("Wrong browser/driver version".into());
} else {
return Err(format!(
"Downloaded file cannot be uncompressed ({} extension)",
extension
)
.into());
}
Ok(())
}
pub fn untargz(file: File, target: PathBuf) -> Result<(), Box<dyn Error>> {
log::trace!("Untargz file to {}", target.display());
let tar = GzDecoder::new(&file);
let mut archive = Archive::new(tar);
let parent_path = target
.parent()
.ok_or(format!("Error getting parent of {:?}", file))?;
if !target.exists() {
archive.unpack(parent_path)?;
}
Ok(())
}
pub fn unzip(file: File, target: PathBuf) -> Result<(), Box<dyn Error>> {
log::trace!("Unzipping file to {}", target.display());
let mut archive = ZipArchive::new(file)?;
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
if target.exists() {
continue;
}
let target_file_name = target.file_name().unwrap().to_str().unwrap();
if target_file_name.eq_ignore_ascii_case(file.name()) {
log::debug!(
"File extracted to {} ({} bytes)",
target.display(),
file.size()
);
if let Some(p) = target.parent() {
create_path_if_not_exists(p);
}
if !target.exists() {
let mut outfile = File::create(&target)?;
// Set permissions in Unix-like systems
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(&target, fs::Permissions::from_mode(0o755))?;
}
io::copy(&mut file, &mut outfile)?;
}
break;
}
}
Ok(())
}
pub fn compose_cache_folder() -> PathBuf {
if let Some(base_dirs) = BaseDirs::new() {
return Path::new(base_dirs.home_dir())
.join(String::from(CACHE_FOLDER).replace('/', &MAIN_SEPARATOR.to_string()));
}
PathBuf::new()
}
pub fn get_cache_folder() -> PathBuf {
let cache_path = compose_cache_folder();
create_path_if_not_exists(&cache_path);
cache_path
}
pub fn compose_driver_path_in_cache(
driver_name: &str,
os: &str,
arch_folder: &str,
driver_version: &str,
) -> PathBuf {
get_cache_folder()
.join(driver_name)
.join(arch_folder)
.join(driver_version)
.join(get_driver_filename(driver_name, os))
}
pub fn get_driver_filename(driver_name: &str, os: &str) -> String {
format!("{}{}", driver_name, get_binary_extension(os))
}
pub fn get_binary_extension(os: &str) -> &str {
if WINDOWS.is(os) {
".exe"
} else {
""
}
}
pub fn parse_version(version_text: String) -> Result<String, Box<dyn Error>> {
if version_text.to_ascii_lowercase().contains("error") {
return Err("Wrong browser/driver version".into());
}
let re = Regex::new(r"[^\d^.]").unwrap();
Ok(re.replace_all(&*version_text, "").to_string())
}