blob: 88aafe9438858e61be1a9a9a99a56930d151e031 [file] [log] [blame]
//! Contains helper types that are capable of dynamically creating project
//! layouts under target/ for testing purposes.
//! This module is currently pulled by main binary and Cargo integration tests.
#![allow(dead_code)]
use walkdir::WalkDir;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use super::paths::{self, TestPathExt};
#[derive(PartialEq, Clone)]
struct FileBuilder {
path: PathBuf,
body: String,
}
impl FileBuilder {
pub fn new(path: PathBuf, body: &str) -> FileBuilder {
FileBuilder { path, body: body.to_string() }
}
fn mk(&self) {
self.dirname().mkdir_p();
let mut file = fs::File::create(&self.path)
.unwrap_or_else(|e| panic!("could not create file {}: {}", self.path.display(), e));
file.write_all(self.body.as_bytes()).unwrap();
}
fn dirname(&self) -> &Path {
self.path.parent().unwrap()
}
}
#[derive(PartialEq, Clone)]
pub struct Project {
root: PathBuf,
}
#[must_use]
#[derive(PartialEq, Clone)]
pub struct ProjectBuilder {
root: Project,
files: Vec<FileBuilder>,
}
impl ProjectBuilder {
pub fn new(root: PathBuf) -> ProjectBuilder {
ProjectBuilder { root: Project { root }, files: vec![] }
}
pub fn try_from_fixture(fixture_dir: impl AsRef<Path>) -> std::io::Result<Self> {
let fixture_dir = fixture_dir.as_ref();
let dirname = fixture_dir
.file_name()
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, "No filename"))?;
// Generate a new, unique directory for working dir under target/
let genroot = paths::root();
let mut builder = ProjectBuilder::new(genroot.join(dirname));
// Read existing fixture data to be later copied into scratch genroot
for entry in WalkDir::new(fixture_dir).into_iter() {
let entry = entry?;
let path = entry.path();
let body = if !std::fs::metadata(path)?.is_dir() {
std::fs::read_to_string(path)?
} else {
continue;
};
let relative = entry.path().strip_prefix(fixture_dir).unwrap();
builder._file(relative, &body);
}
Ok(builder)
}
pub fn file<B: AsRef<Path>>(mut self, path: B, body: &str) -> Self {
self._file(path.as_ref(), body);
self
}
fn _file(&mut self, path: &Path, body: &str) {
self.files.push(FileBuilder::new(self.root.root.join(path), body));
}
pub fn build(self) -> Project {
// First, clean the directory if it already exists
self.rm_root();
// Create the empty directory
self.root.root.mkdir_p();
for file in &self.files {
file.mk();
}
self.root
}
fn rm_root(&self) {
self.root.root.rm_rf()
}
}
impl Project {
pub fn root(&self) -> &Path {
&self.root
}
}
// Generates a project layout
pub fn project(name: &str) -> ProjectBuilder {
ProjectBuilder::new(paths::root().join(name))
}