Skip to content
Snippets Groups Projects
Verified Commit 82443337 authored by Eduardo Trujillo's avatar Eduardo Trujillo
Browse files

refactor(bundle): Use rundir module from collective crate

parent b03081b5
No related branches found
No related tags found
1 merge request!3v2.0.0
use crate::config::Config;
use rundir::RunDir;
use collective::rundir::{self, RunDir};
use s3::packager::S3BundlePackager;
use serde::Serialize;
use snafu::{ResultExt, Snafu};
......@@ -14,19 +14,18 @@ use self::{local_dir::poller::LocalBundlePoller, s3::poller::S3BundlePoller};
pub mod local_dir;
pub mod packager;
pub mod poller;
pub mod rundir;
pub mod s3;
#[derive(Snafu, Debug)]
pub enum Error {
InitRunDir { source: rundir::Error },
DeinitRunDir { source: rundir::Error },
InitRunDir { source: rundir::RunDirError },
DeinitRunDir { source: rundir::RunDirError },
LockRead,
LockWrite,
AttachSignalHook { source: std::io::Error },
MissingETag,
PollError { source: poller::Error },
SubDirError { source: rundir::Error },
SubDirError { source: rundir::RunDirError },
}
type Result<T, E = Error> = std::result::Result<T, E>;
......
use snafu::{ResultExt, Snafu};
use std::path::{Path, PathBuf};
#[derive(Snafu, Debug)]
pub enum Error {
Initialize {
path: PathBuf,
},
PathIsNotDir {
path: PathBuf,
},
DirIsNotEmpty {
path: PathBuf,
child_path: PathBuf,
},
CreateDir {
path: PathBuf,
source: std::io::Error,
},
ScanDir {
path: PathBuf,
source: std::io::Error,
},
RecreateDir {
path: PathBuf,
source: std::io::Error,
},
RemoveSubDir {
path: PathBuf,
source: std::io::Error,
},
InvalidSubDirName {
name: String,
inner_error: Option<std::io::Error>,
},
}
type Result<T, E = Error> = std::result::Result<T, E>;
pub struct RunDir {
path: PathBuf,
allow_cleaning: bool,
}
impl RunDir {
pub fn new<T: Into<PathBuf>>(path: T) -> RunDir {
RunDir {
path: path.into(),
allow_cleaning: false,
}
}
/// Set whether the directory can perform cleanup operations.
///
/// Use with caution. This will clear existing directories on initialization
/// and cleanup.
pub fn allow_cleaning(mut self, allow_cleaning: bool) -> RunDir {
self.allow_cleaning = allow_cleaning;
self
}
/// Creates the initial `RunDir`.
///
/// # Examples
///
/// ```
/// use espresso::bundle::rundir::RunDir;
///
/// let rundir = RunDir::new("tests/rundir").allow_cleaning(true);
///
/// rundir.initialize().unwrap();
///
/// rundir.cleanup().unwrap();
/// ```
pub fn initialize(&self) -> Result<()> {
if Path::exists(&self.path) {
info!("RunDir already exists: {}", self.path.display());
if !Path::is_dir(&self.path) {
error!("RunDir is not a directory: {}", self.path.display());
return Err(Error::PathIsNotDir {
path: self.path.clone(),
});
} else {
// Scan dir
let mut dir_iterator = std::fs::read_dir(&self.path).context(ScanDir {
path: self.path.clone(),
})?;
let existing_child_path = dir_iterator
.next()
.map(|entry_result| entry_result.map(|entry| entry.path()));
if let Some(child_path) = existing_child_path {
let child_path = child_path.context(ScanDir {
path: self.path.clone(),
})?;
if self.allow_cleaning {
info!("Recreating RunDir.");
std::fs::remove_dir_all(&self.path).context(RecreateDir {
path: self.path.clone(),
})?;
std::fs::create_dir_all(&self.path).context(RecreateDir {
path: self.path.clone(),
})?;
} else {
return Err(Error::DirIsNotEmpty {
path: self.path.clone(),
child_path,
});
}
}
}
} else {
info!("Creating new RunDir: {}", self.path.display());
std::fs::create_dir_all(&self.path).context(CreateDir {
path: self.path.clone(),
})?
}
Ok(())
}
pub fn cleanup(&self) -> Result<()> {
if self.allow_cleaning {
std::fs::remove_dir_all(&self.path).context(RecreateDir {
path: self.path.clone(),
})?;
info!("Cleaned up RunDir: {}", self.path.display());
} else {
warn!("Leaving RunDir unmodified. Manual cleanup may be needed.");
}
Ok(())
}
/// Creates a subdir within the `RunDir`.
pub fn create_subdir(&self, name: &str) -> Result<PathBuf> {
let pathbuf = self.validate_subdir_name(name)?;
std::fs::create_dir(&pathbuf).context(CreateDir {
path: pathbuf.clone(),
})?;
Ok(pathbuf)
}
/// Removes a subdir and all its contents from the `RunDir`.
pub fn remove_subdir_all(&self, name: &str) -> Result<()> {
let pathbuf = self.validate_subdir_name(name)?;
std::fs::remove_dir_all(&pathbuf).context(RemoveSubDir { path: pathbuf })?;
Ok(())
}
/// Checks if a subdir exists within the `RunDir`.
pub fn subdir_exists(&self, name: &str) -> Result<bool> {
let pathbuf = self.validate_subdir_name(name)?;
Ok(pathbuf.exists())
}
fn validate_subdir_name(&self, name: &str) -> Result<PathBuf> {
// Check that the name results in a dir exactly one level below the current one.
let mut pathbuf = self.path.clone();
pathbuf.push(name);
if let Some(parent) = pathbuf.parent() {
if *parent != self.path {
return Err(Error::InvalidSubDirName {
name: String::from(name),
inner_error: None,
});
}
} else {
return Err(Error::InvalidSubDirName {
name: String::from(name),
inner_error: None,
});
}
Ok(pathbuf)
}
}
#[cfg(test)]
mod tests {
use super::{Error, RunDir};
use std::path::PathBuf;
#[test]
fn test_initialize() -> () {
// Create dir for the first time.
let result = RunDir::new("tests/rundir").initialize();
assert!(result.is_ok());
// Use existing empty dir.
let result = RunDir::new("tests/rundir").initialize();
assert!(result.is_ok());
// Fail when dir is not empty and allow_cleaning is not set.
std::fs::write("tests/rundir/hello.world", "test").unwrap();
let result = RunDir::new("tests/rundir").initialize();
match result {
Err(Error::DirIsNotEmpty { path, child_path }) => {
assert_eq!(path, PathBuf::from("tests/rundir"));
assert_eq!(child_path, PathBuf::from("tests/rundir/hello.world"));
}
_ => panic!("Expected an error."),
}
// Clean existing dir.
let result = RunDir::new("tests/rundir")
.allow_cleaning(true)
.initialize();
assert!(result.is_ok());
std::fs::remove_dir("tests/rundir").unwrap();
// Fail when dir is not a directory.
std::fs::write("tests/rundir", "hello").unwrap();
let result = RunDir::new("tests/rundir").initialize();
match result {
Err(Error::PathIsNotDir { path }) => {
assert_eq!(path, PathBuf::from("tests/rundir"));
}
_ => panic!("Expected an error."),
}
std::fs::remove_file("tests/rundir").unwrap();
}
#[test]
fn test_subdirs() -> () {
let rundir = RunDir::new("tests/rundir2").allow_cleaning(true);
rundir.initialize().unwrap();
assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), false);
assert_eq!(rundir.subdir_exists("subtest").unwrap(), false);
rundir.create_subdir("subtest").unwrap();
assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), true);
assert_eq!(rundir.subdir_exists("subtest").unwrap(), true);
rundir.remove_subdir_all("subtest").unwrap();
assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), false);
assert_eq!(rundir.subdir_exists("subtest").unwrap(), false);
rundir.cleanup().unwrap();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment