use std::env::var_os;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use anyhow::Result;
use reqwest::blocking::Request;
use url::{Host, Url};
pub fn clone_request(request: &mut Request) -> Result<Request> {
if let Some(b) = request.body_mut().as_mut() {
b.buffer()?;
}
Ok(request.try_clone().unwrap()) }
pub fn test_mode() -> bool {
cfg!(test) || var_os("XH_TEST_MODE").is_some()
}
pub fn test_pretend_term() -> bool {
var_os("XH_TEST_MODE_TERM").is_some()
}
pub fn test_default_color() -> bool {
var_os("XH_TEST_MODE_COLOR").is_some()
}
#[cfg(test)]
pub fn random_string() -> String {
use rand::Rng;
rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(10)
.map(char::from)
.collect()
}
pub fn config_dir() -> Option<PathBuf> {
if let Some(dir) = std::env::var_os("XH_CONFIG_DIR") {
Some(dir.into())
} else {
dirs::config_dir().map(|dir| dir.join("xh"))
}
}
pub fn get_home_dir() -> Option<PathBuf> {
#[cfg(target_os = "windows")]
if let Some(path) = std::env::var_os("XH_TEST_MODE_WIN_HOME_DIR") {
return Some(PathBuf::from(path));
}
dirs::home_dir()
}
pub fn expand_tilde(path: impl AsRef<Path>) -> PathBuf {
if let Ok(path) = path.as_ref().strip_prefix("~") {
let mut expanded_path = PathBuf::new();
expanded_path.push(get_home_dir().unwrap_or_else(|| "~".into()));
expanded_path.push(path);
expanded_path
} else {
path.as_ref().into()
}
}
#[macro_export]
macro_rules! vec_of_strings {
($($str:expr),*) => ({
vec![$(String::from($str),)*] as Vec<String>
});
}
#[macro_export]
macro_rules! regex {
($name:ident = $($re:expr)+) => {
static $name: once_cell::sync::Lazy<regex::Regex> =
once_cell::sync::Lazy::new(|| regex::Regex::new(concat!($($re,)+)).unwrap());
};
($($re:expr)+) => {{
static RE: once_cell::sync::Lazy<regex::Regex> =
once_cell::sync::Lazy::new(|| regex::Regex::new(concat!($($re,)+)).unwrap());
&RE
}};
}
pub const BUFFER_SIZE: usize = 128 * 1024;
pub fn copy_largebuf(
reader: &mut impl io::Read,
writer: &mut impl Write,
flush: bool,
) -> io::Result<()> {
let mut buf = vec![0; BUFFER_SIZE];
loop {
match reader.read(&mut buf) {
Ok(0) => return Ok(()),
Ok(len) => {
writer.write_all(&buf[..len])?;
if flush {
writer.flush()?;
}
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
}
}
pub fn url_requires_native_tls(url: &Url) -> bool {
url.scheme() == "https" && matches!(url.host(), Some(Host::Ipv4(..)) | Some(Host::Ipv6(..)))
}