no hash can process file path and extension combinations
This commit is contained in:
parent
081ec4c286
commit
3cf8828ab8
2 changed files with 165 additions and 32 deletions
|
@ -64,6 +64,7 @@
|
||||||
|
|
||||||
pub mod processor;
|
pub mod processor;
|
||||||
pub use processor::BusterBuilder;
|
pub use processor::BusterBuilder;
|
||||||
|
pub use processor::NoHashCategory;
|
||||||
pub mod filemap;
|
pub mod filemap;
|
||||||
pub use filemap::Files;
|
pub use filemap::Files;
|
||||||
|
|
||||||
|
|
196
src/processor.rs
196
src/processor.rs
|
@ -47,6 +47,26 @@ use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// Items to avoid hash calculation.
|
||||||
|
///
|
||||||
|
/// This is useful when serving vendor static files which are interlinked, where chaing
|
||||||
|
/// file names should mean changing how the vendor files pulls its dependencies --- which are
|
||||||
|
/// beyond the abilities of `cache_buster`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cache_buster::NoHashCategory;
|
||||||
|
///
|
||||||
|
/// let extensions = NoHashCategory::FileExtentions(vec!["wasm"]);
|
||||||
|
/// let files = NoHashCategory::FileExtentions(vec!["swagger-ui-bundle.js", "favicon-16x16.png"]);
|
||||||
|
/// ```
|
||||||
|
pub enum NoHashCategory<'a> {
|
||||||
|
/// vector of file extensions that should be avoided for hash processing
|
||||||
|
FileExtentions(Vec<&'a str>),
|
||||||
|
/// list of file paths that should be avoided for file processing
|
||||||
|
FilePaths(Vec<&'a str>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration for setting up cache-busting
|
/// Configuration for setting up cache-busting
|
||||||
#[derive(Debug, Clone, Builder)]
|
#[derive(Debug, Clone, Builder)]
|
||||||
#[builder(build_fn(validate = "Self::validate"))]
|
#[builder(build_fn(validate = "Self::validate"))]
|
||||||
|
@ -71,18 +91,22 @@ pub struct Buster<'a> {
|
||||||
/// They will be copied over without including a hash in the filename
|
/// They will be copied over without including a hash in the filename
|
||||||
/// Path should be relative to [self.source]
|
/// Path should be relative to [self.source]
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
no_hash: Vec<&'a str>,
|
no_hash: Vec<NoHashCategory<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BusterBuilder<'a> {
|
impl<'a> BusterBuilder<'a> {
|
||||||
fn validate(&self) -> Result<(), String> {
|
fn validate(&self) -> Result<(), String> {
|
||||||
for file in self.no_hash.iter() {
|
for no_hash_configs in self.no_hash.iter() {
|
||||||
for file in file.iter() {
|
for no_hash in no_hash_configs.iter() {
|
||||||
if !Path::new(&self.source.as_ref().unwrap())
|
if let NoHashCategory::FilePaths(files) = no_hash {
|
||||||
.join(file)
|
for file in files.iter() {
|
||||||
.exists()
|
if !Path::new(&self.source.as_ref().unwrap())
|
||||||
{
|
.join(file)
|
||||||
return Err(format!("File {} doesn't exist", file));
|
.exists()
|
||||||
|
{
|
||||||
|
return Err(format!("File {} doesn't exist", file));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,23 +148,64 @@ impl<'a> Buster<'a> {
|
||||||
let mut process_worker = |path: &Path| {
|
let mut process_worker = |path: &Path| {
|
||||||
let contents = Self::read_to_string(&path).unwrap();
|
let contents = Self::read_to_string(&path).unwrap();
|
||||||
let hash = Self::hasher(&contents);
|
let hash = Self::hasher(&contents);
|
||||||
let new_name = if self.no_hash.iter().any(|no_hash| {
|
|
||||||
let no_hash = Path::new(&self.source).join(&no_hash);
|
let get_name = |no_hash: bool| -> String {
|
||||||
no_hash == path
|
if no_hash {
|
||||||
}) {
|
format!(
|
||||||
format!(
|
"{}.{}",
|
||||||
"{}.{}",
|
path.file_stem().unwrap().to_str().unwrap(),
|
||||||
path.file_stem().unwrap().to_str().unwrap(),
|
path.extension().unwrap().to_str().unwrap()
|
||||||
path.extension().unwrap().to_str().unwrap()
|
)
|
||||||
)
|
} else {
|
||||||
} else {
|
format!(
|
||||||
format!(
|
"{}.{}.{}",
|
||||||
"{}.{}.{}",
|
path.file_stem().unwrap().to_str().unwrap(),
|
||||||
path.file_stem().unwrap().to_str().unwrap(),
|
hash,
|
||||||
hash,
|
path.extension().unwrap().to_str().unwrap()
|
||||||
path.extension().unwrap().to_str().unwrap()
|
)
|
||||||
)
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let no_hash_status = self.no_hash.iter().any(|no_hash| {
|
||||||
|
match no_hash {
|
||||||
|
NoHashCategory::FilePaths(paths) => {
|
||||||
|
let no_hash_status = paths
|
||||||
|
.iter()
|
||||||
|
.any(|file_path| Path::new(&self.source).join(&file_path) == path);
|
||||||
|
no_hash_status
|
||||||
|
}
|
||||||
|
NoHashCategory::FileExtentions(extensions) => {
|
||||||
|
let mut no_hash_status = false;
|
||||||
|
if let Some(cur_extention) = path.extension() {
|
||||||
|
// .unwrap().to_str().unwrap();
|
||||||
|
if let Some(cur_extention) = cur_extention.to_str() {
|
||||||
|
no_hash_status = extensions.iter().any(|ext| &cur_extention == ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
no_hash_status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let new_name = get_name(no_hash_status);
|
||||||
|
|
||||||
|
// let new_name = if self.no_hash.iter().any(|no_hash| {
|
||||||
|
// let no_hash = Path::new(&self.source).join(&no_hash);
|
||||||
|
// no_hash == path
|
||||||
|
// }) {
|
||||||
|
// format!(
|
||||||
|
// "{}.{}",
|
||||||
|
// path.file_stem().unwrap().to_str().unwrap(),
|
||||||
|
// path.extension().unwrap().to_str().unwrap()
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// format!(
|
||||||
|
// "{}.{}.{}",
|
||||||
|
// path.file_stem().unwrap().to_str().unwrap(),
|
||||||
|
// hash,
|
||||||
|
// path.extension().unwrap().to_str().unwrap()
|
||||||
|
// )
|
||||||
|
// };
|
||||||
self.copy(path, &new_name);
|
self.copy(path, &new_name);
|
||||||
let (source, destination) = self.gen_map(path, &&new_name);
|
let (source, destination) = self.gen_map(path, &&new_name);
|
||||||
let _ = file_map.add(
|
let _ = file_map.add(
|
||||||
|
@ -313,7 +378,9 @@ pub mod tests {
|
||||||
mime::IMAGE_GIF,
|
mime::IMAGE_GIF,
|
||||||
];
|
];
|
||||||
|
|
||||||
let no_hash = vec!["bbell.svg", "eye.svg", "a/b/c/d/s/d/svg/10.svg"];
|
let no_hash =
|
||||||
|
NoHashCategory::FilePaths(vec!["bbell.svg", "eye.svg", "a/b/c/d/s/d/svg/10.svg"]);
|
||||||
|
|
||||||
assert!(BusterBuilder::default()
|
assert!(BusterBuilder::default()
|
||||||
.source("./dist")
|
.source("./dist")
|
||||||
.result("/tmp/prod2i")
|
.result("/tmp/prod2i")
|
||||||
|
@ -321,27 +388,28 @@ pub mod tests {
|
||||||
.copy(true)
|
.copy(true)
|
||||||
.follow_links(true)
|
.follow_links(true)
|
||||||
.prefix("/test")
|
.prefix("/test")
|
||||||
.no_hash(no_hash.clone())
|
.no_hash(vec![no_hash.clone()])
|
||||||
.build()
|
.build()
|
||||||
.is_err())
|
.is_err())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_specific_mime() {
|
fn no_specific_mime() {
|
||||||
delete_file();
|
delete_file();
|
||||||
use std::{thread, time};
|
//use std::{thread, time};
|
||||||
|
|
||||||
let sleep = time::Duration::from_secs(4);
|
//let sleep = time::Duration::from_secs(4);
|
||||||
|
|
||||||
thread::sleep(sleep);
|
//thread::sleep(sleep);
|
||||||
|
|
||||||
const WASM: &str = "858fd6c482cc75111d54.module.wasm";
|
const WASM: &str = "858fd6c482cc75111d54.module.wasm";
|
||||||
let no_hash = vec![WASM, "bell.svg", "eye.svg", "a/b/c/d/s/d/svg/10.svg"];
|
let no_hash_files = vec![WASM, "bell.svg", "eye.svg", "a/b/c/d/s/d/svg/10.svg"];
|
||||||
|
let no_hash = NoHashCategory::FilePaths(no_hash_files.clone());
|
||||||
let config = BusterBuilder::default()
|
let config = BusterBuilder::default()
|
||||||
.source("./dist")
|
.source("./dist")
|
||||||
.result("/tmp/prod2ii")
|
.result("/tmp/prod2ii")
|
||||||
.copy(true)
|
.copy(true)
|
||||||
.follow_links(true)
|
.follow_links(true)
|
||||||
.no_hash(no_hash.clone())
|
.no_hash(vec![no_hash.clone()])
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
config.process().unwrap();
|
config.process().unwrap();
|
||||||
|
@ -356,7 +424,7 @@ pub mod tests {
|
||||||
&& source.file_name() == dest.file_name()
|
&& source.file_name() == dest.file_name()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
no_hash.iter().for_each(|file| {
|
no_hash_files.iter().for_each(|file| {
|
||||||
assert!(files.map.iter().any(|(k, v)| {
|
assert!(files.map.iter().any(|(k, v)| {
|
||||||
let source = Path::new(k);
|
let source = Path::new(k);
|
||||||
let dest = Path::new(&v);
|
let dest = Path::new(&v);
|
||||||
|
@ -411,8 +479,72 @@ pub mod tests {
|
||||||
cleanup(&config);
|
cleanup(&config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn no_hash_extension_works() {
|
||||||
|
delete_file();
|
||||||
|
use std::{thread, time};
|
||||||
|
|
||||||
|
let sleep = time::Duration::from_secs(4);
|
||||||
|
const APPLICATION_WASM: &str = "wasm";
|
||||||
|
const WASM: &str = "858fd6c482cc75111d54.module.wasm";
|
||||||
|
|
||||||
|
thread::sleep(sleep);
|
||||||
|
|
||||||
|
let no_hash_extensions = vec![APPLICATION_WASM];
|
||||||
|
let no_hash_ext = NoHashCategory::FileExtentions(no_hash_extensions.clone());
|
||||||
|
|
||||||
|
let no_hash_paths = vec!["bell.svg", "eye.svg", "a/b/c/d/s/d/svg/10.svg"];
|
||||||
|
let no_hash_cat = NoHashCategory::FilePaths(no_hash_paths.clone());
|
||||||
|
let no_hash = vec![no_hash_cat, no_hash_ext];
|
||||||
|
|
||||||
|
let config = BusterBuilder::default()
|
||||||
|
.source("./dist")
|
||||||
|
.result("/tmp/prodnohashextension")
|
||||||
|
.copy(true)
|
||||||
|
.follow_links(true)
|
||||||
|
.no_hash(no_hash.clone())
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
config.process().unwrap();
|
||||||
|
let files = Files::load();
|
||||||
|
|
||||||
|
assert!(files.map.iter().any(|(k, v)| {
|
||||||
|
let dest = Path::new(&v);
|
||||||
|
dest.extension().unwrap().to_str().unwrap() == APPLICATION_WASM && dest.exists()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let no_hash_file = Path::new(&config.result).join(WASM);
|
||||||
|
assert!(files.map.iter().any(|(k, v)| {
|
||||||
|
let source = Path::new(&config.source).join(k);
|
||||||
|
let dest = Path::new(&v);
|
||||||
|
dest.file_name() == no_hash_file.file_name()
|
||||||
|
&& dest.exists()
|
||||||
|
&& source.file_name() == dest.file_name()
|
||||||
|
}));
|
||||||
|
|
||||||
|
no_hash_paths.iter().for_each(|file| {
|
||||||
|
assert!(files.map.iter().any(|(k, v)| {
|
||||||
|
let source = Path::new(k);
|
||||||
|
let dest = Path::new(&v);
|
||||||
|
let no_hash = Path::new(file);
|
||||||
|
source == &Path::new(&config.source).join(file)
|
||||||
|
&& dest.exists()
|
||||||
|
&& no_hash.file_name() == dest.file_name()
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (k, v) in files.map.iter() {
|
||||||
|
let src = Path::new(&k);
|
||||||
|
let dest = Path::new(&v);
|
||||||
|
|
||||||
|
assert_eq!(src.exists(), dest.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup(&config);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn runner() {
|
pub fn runner() {
|
||||||
prefix_works();
|
prefix_works();
|
||||||
no_specific_mime();
|
no_specific_mime();
|
||||||
|
no_hash_extension_works();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue