use std::{
fs::File,
io::{Read, Write},
path::Path
};
use anyhow::{bail, Context, Result};
const LOCAL_UNC: &str = "\\\\?\\";
pub fn strip_unc(path: &Path) -> String {
let path_to_refine = path.to_str().unwrap_or("");
if path_to_refine.is_empty() {
path.to_string_lossy().trim_start_matches(LOCAL_UNC).to_string()
} else {
path_to_refine.trim_start_matches(LOCAL_UNC).to_string()
}
}
pub fn create_file(path: &Path, content: &str) -> Result<()> {
let mut file = File::create(path).with_context(|| format!("Failed to create File {}", path.display()))?;
file.write_all(content.as_bytes())?;
Ok(())
}
pub fn load_json_file(file_path: &Path) -> Result<serde_json::Value> {
let mut file = File::open(file_path).with_context(|| format!("Failed to open file {}", file_path.display()))?;
let mut file_string = String::new();
file.read_to_string(&mut file_string)?;
Ok(serde_json::from_str(&file_string)?)
}
pub fn is_directory_empty(path: &Path, allow_hidden: bool) -> Result<bool> {
if path.is_dir() {
let mut entries = match path.read_dir() {
Ok(entries) => entries,
Err(e) => bail!("Could not read '{}' because of error: {}", path.to_string_lossy().to_string(), e),
};
if entries.any(|x| match x {
Ok(file) => {
if allow_hidden {
!file.file_name().to_str().unwrap_or("").starts_with('.')
} else {
true
}
},
Err(_) => true,
}) {
return Ok(false);
}
return Ok(true);
}
Ok(false)
}
pub mod console {
pub fn error(msg: &str, e: Option<impl std::fmt::Debug>) {
log::error!("{}", msg);
if let Some(e) = e {
log::error!("{:?}", e);
}
}
pub fn error_exit(msg: &str, e: Option<impl std::fmt::Debug>) {
error(msg, e);
std::process::exit(1);
}
pub fn warn(msg: &str) {
log::warn!("{}", msg);
}
pub fn info(msg: &str) {
log::info!("{}", msg);
}
pub fn success_exit(msg: &str) {
info(msg);
std::process::exit(0);
}
#[cfg(debug_assertions)]
pub fn debug(msg: &str) {
log::debug!("{}", msg);
}
#[cfg(not(debug_assertions))]
pub fn debug(_msg: &str) {}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{
env::temp_dir,
fs::{canonicalize, create_dir, remove_dir_all},
path::{Path, PathBuf}
};
fn get_temp_dir(path: &str, create: bool) -> PathBuf {
let mut dir = temp_dir();
dir.push(path);
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
if create {
create_dir(&dir).expect("Could not create test directory");
}
dir
}
#[test]
fn strip_unc_test() {
let dir = get_temp_dir("test_strip_unc", true);
if cfg!(target_os = "windows") {
let canonicalized = canonicalize(Path::new(&dir)).expect("Failed to canonicalize path");
let stripped_path = strip_unc(&canonicalized);
assert!(same_file::is_same_file(Path::new(&stripped_path), &dir).expect("Failed to compare files"));
assert!(!stripped_path.starts_with(LOCAL_UNC), "The path was not stripped.");
} else {
let canonicalized = canonicalize(Path::new(&dir)).expect("Failed to canonicalize path");
assert_eq!(
strip_unc(&canonicalized),
canonicalized.to_str().expect("Failed to convert path to str").to_string()
);
}
remove_dir_all(&dir).expect("Failed to remove test directory");
}
#[test]
#[cfg(target_os = "windows")]
fn strip_unc_required_test() {
let dir = get_temp_dir("test_strip_unc_required", true);
let canonicalized_path = canonicalize(Path::new(&dir)).expect("Failed to canonicalize path");
assert!(same_file::is_same_file(Path::new(&canonicalized_path), &dir).expect("Failed to compare files"));
assert!(canonicalized_path.to_str().expect("Failed to convert path to str").starts_with(LOCAL_UNC));
remove_dir_all(&dir).expect("Failed to remove test directory");
}
#[test]
fn create_file_test() {
let dir = get_temp_dir("test_create_file", true);
let file_path = dir.join("test_file.txt");
create_file(&file_path, "test content").expect("Could not create file");
assert!(file_path.exists());
remove_dir_all(&dir).expect("Failed to remove test directory");
}
}