use retry::{delay, retry};
use std::env;
use std::error;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use crate::errors::*;
#[macro_export]
macro_rules! err {
($( $e:expr ),+) => ($crate::err(&format!($( $e ),+)))
}
pub fn err(msg: &str) -> Error {
msg.into()
}
pub trait ToStrOrErr {
fn to_str_or_err(&self) -> Result<&str>;
}
impl ToStrOrErr for OsStr {
fn to_str_or_err(&self) -> Result<&str> {
self.to_str().ok_or_else(|| {
err!("the string {:?} contains non-Unicode characters", self)
})
}
}
impl ToStrOrErr for Path {
fn to_str_or_err(&self) -> Result<&str> {
self.to_str().ok_or_else(|| {
err!(
"the path {} contains non-Unicode characters",
self.display()
)
})
}
}
pub trait ConductorPathExt: ToStrOrErr {
fn glob(&self, pattern: &str) -> Result<glob::Paths>;
fn with_guaranteed_parent(&self) -> Result<PathBuf>;
fn to_absolute(&self) -> Result<PathBuf>;
}
impl ConductorPathExt for Path {
fn glob(&self, pattern: &str) -> Result<glob::Paths> {
let opts = glob::MatchOptions {
case_sensitive: true,
require_literal_separator: true,
require_literal_leading_dot: true,
};
let pat = format!("{}/{}", self.to_str_or_err()?, pattern);
Ok(glob::glob_with(&pat, opts)?)
}
fn with_guaranteed_parent(&self) -> Result<PathBuf> {
let parent = self
.parent()
.ok_or_else(|| err!("can't find parent path of {}", self.display()))?;
let wrap_err = |err: &dyn error::Error| -> Error {
err!(
"error creating parent directories for {}: {}",
parent.display(),
err
)
};
let delay = delay::Fixed::from_millis(50).take(10);
retry(delay, || match fs::create_dir_all(&parent) {
Ok(()) => Ok(()),
Err(ref err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(()),
Err(err) => Err(err),
})
.map_err(|e| wrap_err(&e))?;
Ok(self.to_owned())
}
fn to_absolute(&self) -> Result<PathBuf> {
let path = env::current_dir()?.join(self);
assert!(path.is_absolute());
Ok(path)
}
}
#[test]
fn path_glob_uses_path_as_base() {
let base = Path::new("examples/hello/pods/targets");
let paths: Vec<_> = base
.glob("test/*.env")
.unwrap()
.map(|p| p.unwrap().strip_prefix(base).unwrap().to_owned())
.collect();
assert_eq!(paths, vec![Path::new("test/common.env")]);
}