pub mod identity;
pub mod pipeline;
pub mod template;
pub mod unarchive;
use std::path::{Path, PathBuf};
use serde::Serialize;
use crate::fs::Fs;
use crate::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum TransformType {
Generative,
Representational,
Opaque,
}
#[derive(Debug, Clone)]
pub struct ExpandedFile {
pub relative_path: PathBuf,
pub content: Vec<u8>,
pub is_dir: bool,
}
pub trait Preprocessor: Send + Sync {
fn name(&self) -> &str;
fn transform_type(&self) -> TransformType;
fn matches_extension(&self, filename: &str) -> bool;
fn stripped_name(&self, filename: &str) -> String;
fn expand(&self, source: &Path, fs: &dyn Fs) -> Result<Vec<ExpandedFile>>;
}
pub struct PreprocessorRegistry {
preprocessors: Vec<Box<dyn Preprocessor>>,
}
impl PreprocessorRegistry {
pub fn new() -> Self {
Self {
preprocessors: Vec::new(),
}
}
pub fn register(&mut self, preprocessor: Box<dyn Preprocessor>) {
self.preprocessors.push(preprocessor);
}
pub fn find_for_file(&self, filename: &str) -> Option<&dyn Preprocessor> {
self.preprocessors
.iter()
.find(|p| p.matches_extension(filename))
.map(|p| p.as_ref())
}
pub fn is_preprocessor_file(&self, filename: &str) -> bool {
self.find_for_file(filename).is_some()
}
pub fn is_empty(&self) -> bool {
self.preprocessors.is_empty()
}
pub fn len(&self) -> usize {
self.preprocessors.len()
}
}
impl Default for PreprocessorRegistry {
fn default() -> Self {
Self::new()
}
}
pub fn default_registry(
template_config: &crate::config::PreprocessorTemplateSection,
pather: &dyn crate::paths::Pather,
) -> Result<PreprocessorRegistry> {
let mut registry = PreprocessorRegistry::new();
registry.register(Box::new(unarchive::UnarchivePreprocessor::new()));
registry.register(Box::new(template::TemplatePreprocessor::new(
template_config.extensions.clone(),
template_config.vars.clone(),
pather,
)?));
Ok(registry)
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
fn assert_object_safe(_: &dyn Preprocessor) {}
#[allow(dead_code)]
fn assert_boxable(_: Box<dyn Preprocessor>) {}
#[test]
fn transform_type_eq() {
assert_eq!(TransformType::Generative, TransformType::Generative);
assert_ne!(TransformType::Generative, TransformType::Opaque);
}
#[test]
fn empty_registry() {
let registry = PreprocessorRegistry::new();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
assert!(!registry.is_preprocessor_file("anything.txt"));
assert!(registry.find_for_file("anything.txt").is_none());
}
#[test]
fn registry_finds_preprocessor() {
let mut registry = PreprocessorRegistry::new();
registry.register(Box::new(
crate::preprocessing::identity::IdentityPreprocessor::new(),
));
assert!(!registry.is_empty());
assert_eq!(registry.len(), 1);
assert!(registry.is_preprocessor_file("config.toml.identity"));
assert!(!registry.is_preprocessor_file("config.toml"));
let found = registry.find_for_file("config.toml.identity").unwrap();
assert_eq!(found.name(), "identity");
}
#[test]
fn registry_first_match_wins() {
let mut registry = PreprocessorRegistry::new();
registry.register(Box::new(
crate::preprocessing::identity::IdentityPreprocessor::new(),
));
registry.register(Box::new(
crate::preprocessing::identity::IdentityPreprocessor::with_extension("identity"),
));
let found = registry.find_for_file("test.identity").unwrap();
assert_eq!(found.name(), "identity");
}
#[test]
fn registry_multiple_different_preprocessors() {
let mut registry = PreprocessorRegistry::new();
registry.register(Box::new(
crate::preprocessing::identity::IdentityPreprocessor::new(),
));
registry.register(Box::new(
crate::preprocessing::unarchive::UnarchivePreprocessor::new(),
));
assert_eq!(registry.len(), 2);
assert!(registry.is_preprocessor_file("config.toml.identity"));
assert!(registry.is_preprocessor_file("bin.tar.gz"));
let identity = registry.find_for_file("config.toml.identity").unwrap();
assert_eq!(identity.name(), "identity");
let unarchive = registry.find_for_file("bin.tar.gz").unwrap();
assert_eq!(unarchive.name(), "unarchive");
assert!(registry.find_for_file("regular.txt").is_none());
}
#[test]
fn registry_does_not_match_partial_extension() {
let mut registry = PreprocessorRegistry::new();
registry.register(Box::new(
crate::preprocessing::identity::IdentityPreprocessor::new(),
));
assert!(!registry.is_preprocessor_file("identity"));
assert!(!registry.is_preprocessor_file("fileidentity"));
}
}