use error::*;
use fs::{create_file, create_symlink};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
const TEMP_DIR_NAME_RAND_CHARS: usize = 32;
const TEMP_DIR_RAND_RETRIES: usize = 1024;
pub struct Dir {
path: PathBuf,
}
impl Dir {
pub fn new(prefix: &str) -> Result<Dir> {
Dir::new_in(&env::temp_dir(), prefix)
}
fn new_in<P: AsRef<Path>>(temp_dir: P, prefix: &str) -> Result<Dir> {
let mut rng = thread_rng();
for _ in 0..TEMP_DIR_RAND_RETRIES {
let suffix: String = rng.sample_iter(&Alphanumeric)
.take(TEMP_DIR_NAME_RAND_CHARS)
.collect();
let name = if prefix.is_empty() {
suffix
} else {
format!("{}-{}", prefix, suffix)
};
let path = temp_dir.as_ref().join(&name);
match fs::create_dir(&path) {
Ok(_) => return Ok(Dir { path: path }),
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {}
Err(e) => return Err(e.into()),
}
}
return Err(Error::Io(::std::io::Error::new(
::std::io::ErrorKind::AlreadyExists,
"Failed to find unique random temporary directory name",
)));
}
pub fn path(&self) -> &Path {
self.path.as_path()
}
pub fn sub_path<P: AsRef<Path>>(&self, path: P) -> Result<PathBuf> {
if path.as_ref().is_absolute() {
return Err(Error::InvalidArgument(format_err!(
"Cannot add absolute path '{}' to temporary directory path",
path.as_ref().display()
)));
}
Ok(self.path.as_path().join(path))
}
fn close_impl(&self) -> Result<()> {
Ok(fs::remove_dir_all(&self.path)?)
}
pub fn close(self) -> Result<()> {
self.close_impl()
}
}
impl Drop for Dir {
#[allow(unused_must_use)]
fn drop(&mut self) {
self.close_impl();
}
}
pub struct File {
_dir: Option<Dir>,
path: PathBuf,
}
impl File {
pub fn new_file() -> Result<File> {
let dir = Dir::new("bdrck")?;
let path = dir.sub_path("tempfile")?;
let ret = File {
_dir: Some(dir),
path: path,
};
create_file(ret.path.as_path())?;
Ok(ret)
}
pub fn new_symlink<T: AsRef<Path>>(target: T) -> Result<File> {
let dir = Dir::new("bdrck")?;
let path = dir.sub_path("tempfile")?;
let ret = File {
_dir: Some(dir),
path: path,
};
create_symlink(target, ret.path.as_path())?;
Ok(ret)
}
pub fn new_file_at<P: AsRef<Path>>(path: P) -> Result<File> {
let ret = File {
_dir: None,
path: path.as_ref().to_path_buf(),
};
if let Some(parent) = path.as_ref().parent() {
fs::create_dir_all(parent)?;
}
create_file(ret.path.as_path())?;
Ok(ret)
}
pub fn new_symlink_at<T: AsRef<Path>, S: AsRef<Path>>(target: T, symlink: S) -> Result<File> {
let ret = File {
_dir: None,
path: symlink.as_ref().to_path_buf(),
};
if let Some(parent) = symlink.as_ref().parent() {
fs::create_dir_all(parent)?;
}
create_symlink(target, symlink)?;
Ok(ret)
}
pub fn path(&self) -> &Path {
self.path.as_path()
}
fn close_impl(&self) -> Result<()> {
Ok(fs::remove_file(self.path.as_path())?)
}
pub fn close(self) -> Result<()> {
self.close_impl()
}
}
impl Drop for File {
#[allow(unused_must_use)]
fn drop(&mut self) {
self.close_impl();
}
}