write filemap to file
This commit is contained in:
parent
d5593b2db6
commit
3c3b61aebf
9 changed files with 87 additions and 116 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ prod
|
|||
tarpaulin-report.html
|
||||
actix-example/target
|
||||
actix-example/prod
|
||||
prod56/
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,17 +1,32 @@
|
|||
## 0.2.0
|
||||
|
||||
### Changed:
|
||||
|
||||
- `Files::new()` takes a `&str`: Earlier versions were using
|
||||
environment variables to pass filemap information from `build.rs`
|
||||
component to program code but this proved to be unreliable. Starting
|
||||
with `0.2.0`, `cache_buster` will write filemap to
|
||||
`CACHE_BUSTER_DATA_FILE`(`./src/cache_buster_data.json`) and the user
|
||||
is requested to read and pass the value to `File::new()`
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Added:
|
||||
|
||||
- Optional route prefix to `Processor`
|
||||
|
||||
### Changed:
|
||||
|
||||
- `Files::load()` became `Files::new()`
|
||||
|
||||
### Removed:
|
||||
|
||||
- Some methods on `Files` were for internal use only but they had a
|
||||
public API, they were modified to private.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Added:
|
||||
|
||||
- `SHA-256`-based cache-buster
|
||||
- runtime filemap loading
|
||||
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -21,7 +21,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cache-buster"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"data-encoding",
|
||||
"derive_builder",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "cache-buster"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
authors = ["realaravinth <realaravinth@batsense.net>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
@ -22,7 +22,7 @@ mime = "0.3.16"
|
|||
|
||||
sha2 = "0.9.3"
|
||||
|
||||
derive_builder = "0.10.0"
|
||||
derive_builder = "0.10.2"
|
||||
|
||||
data-encoding = "2.3.2"
|
||||
walkdir = "2"
|
||||
|
|
1
actix-example/src/cache_buster_data.json
Normal file
1
actix-example/src/cache_buster_data.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,8 @@
|
|||
use cache_buster::Files;
|
||||
use cache_buster::CACHE_BUSTER_DATA_FILE;
|
||||
|
||||
fn main() {
|
||||
let files = Files::new();
|
||||
let files = Files::new(CACHE_BUSTER_DATA_FILE);
|
||||
|
||||
assert!(get_full_path_runner("../dist/log-out.svg", &files));
|
||||
assert!(get_full_path_runner(
|
||||
|
|
|
@ -10,19 +10,17 @@
|
|||
//!
|
||||
//! ```no_run
|
||||
//! use cache_buster::Files;
|
||||
//! use cache_buster::CACHE_BUSTER_DATA_FILE;
|
||||
//!
|
||||
//! fn main(){
|
||||
//! let files = Files::new();
|
||||
//! let files = Files::new(CACHE_BUSTER_DATA_FILE);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const ENV_VAR_NAME: &str = "CACHE_BUSTER_FILE_MAP";
|
||||
|
||||
/// Filemap struct
|
||||
///
|
||||
/// maps original names to generated names
|
||||
|
@ -35,10 +33,8 @@ pub struct Files {
|
|||
|
||||
impl Files {
|
||||
/// Load filemap in main program. Should be called from main program
|
||||
pub fn new() -> Self {
|
||||
let env = env::var(ENV_VAR_NAME)
|
||||
.expect("unable to read env var, might be a bug in lib. Please report on GitHub");
|
||||
let res: Files = serde_json::from_str(&env).unwrap();
|
||||
pub fn new(map: &str) -> Self {
|
||||
let res: Files = serde_json::from_str(&map).unwrap();
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -48,7 +44,8 @@ impl Files {
|
|||
/// output `/test.randomhash.svg`. For full path, see [get_full_path][Self::get_full_path].
|
||||
pub fn get<'a>(&'a self, path: &'a str) -> Option<&'a str> {
|
||||
if let Some(path) = self.map.get(path) {
|
||||
Some(&path[self.base_dir.len()..])
|
||||
//Some(&path[self.base_dir.len()..])
|
||||
Some(&path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -65,14 +62,17 @@ impl Files {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::processor::tests::cleanup;
|
||||
use std::fs;
|
||||
|
||||
use crate::processor::tests::{cleanup, delete_file, runner as processor_runner};
|
||||
use crate::processor::*;
|
||||
use crate::CACHE_BUSTER_DATA_FILE;
|
||||
|
||||
use super::*;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn get_full_path_works() {
|
||||
delete_file();
|
||||
let types = vec![
|
||||
mime::IMAGE_PNG,
|
||||
mime::IMAGE_SVG,
|
||||
|
@ -82,7 +82,7 @@ mod tests {
|
|||
|
||||
let config = BusterBuilder::default()
|
||||
.source("./dist")
|
||||
.result("/tmp/prod2")
|
||||
.result("/tmp/prodsd2")
|
||||
.mime_types(types)
|
||||
.copy(true)
|
||||
.follow_links(true)
|
||||
|
@ -91,7 +91,9 @@ mod tests {
|
|||
|
||||
config.process().unwrap();
|
||||
|
||||
let files = Files::new();
|
||||
let map = fs::read_to_string(CACHE_BUSTER_DATA_FILE).unwrap();
|
||||
let files = Files::new(&map);
|
||||
|
||||
assert!(get_full_path_runner("./dist/log-out.svg", &files));
|
||||
assert!(get_full_path_runner(
|
||||
"./dist/a/b/c/d/s/d/svg/credit-card.svg",
|
||||
|
@ -114,8 +116,8 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_works() {
|
||||
delete_file();
|
||||
let types = vec![
|
||||
mime::IMAGE_PNG,
|
||||
mime::IMAGE_SVG,
|
||||
|
@ -134,7 +136,8 @@ mod tests {
|
|||
|
||||
config.process().unwrap();
|
||||
|
||||
let files = Files::new();
|
||||
let map = fs::read_to_string(CACHE_BUSTER_DATA_FILE).unwrap();
|
||||
let files = Files::new(&map);
|
||||
|
||||
assert!(get_runner("./dist/log-out.svg", &files));
|
||||
assert!(get_runner("./dist/a/b/c/d/s/d/svg/credit-card.svg", &files));
|
||||
|
@ -146,10 +149,19 @@ mod tests {
|
|||
|
||||
fn get_runner(path: &str, files: &Files) -> bool {
|
||||
if let Some(file) = files.get(path) {
|
||||
let path = Path::new(&files.base_dir).join(&file[1..]);
|
||||
// let path = Path::new(&files.base_dir).join(&file[1..]);
|
||||
println!("{}", &file);
|
||||
let path = Path::new(&file);
|
||||
path.exists()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn runner() {
|
||||
get_works();
|
||||
get_full_path_works();
|
||||
processor_runner();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,5 +36,6 @@ pub use processor::BusterBuilder;
|
|||
pub mod filemap;
|
||||
pub use filemap::Files;
|
||||
|
||||
/// env var to which filemap is written during compilation
|
||||
pub const ENV_VAR_NAME: &str = "CACHE_BUSTER_FILE_MAP";
|
||||
/// file to which filemap is written during compilation
|
||||
/// include this to `.gitignore`
|
||||
pub const CACHE_BUSTER_DATA_FILE: &str = "./src/cache_buster_data.json";
|
||||
|
|
128
src/processor.rs
128
src/processor.rs
|
@ -47,7 +47,7 @@ use derive_builder::Builder;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::ENV_VAR_NAME;
|
||||
use crate::*;
|
||||
|
||||
/// Configuration for setting up cache-busting
|
||||
#[derive(Debug, Clone, Builder)]
|
||||
|
@ -77,7 +77,6 @@ impl Buster {
|
|||
fs::remove_dir_all(&self.result).unwrap();
|
||||
}
|
||||
|
||||
println!("{}", &self.result);
|
||||
fs::create_dir(&self.result).unwrap();
|
||||
self.create_dir_structure(Path::new(&self.source))?;
|
||||
Ok(())
|
||||
|
@ -93,53 +92,7 @@ impl Buster {
|
|||
|
||||
/// Processes files.
|
||||
///
|
||||
/// If MIME types are uncommon, then use this funtion
|
||||
/// as it won't panic when a weird MIM is encountered.
|
||||
///
|
||||
/// Otherwise, use [process][Self::process]
|
||||
///
|
||||
/// Note: it omits processing uncommon MIME types
|
||||
pub fn try_process(&self) -> Result<(), Error> {
|
||||
self.init()?;
|
||||
let mut file_map: Files = Files::new(&self.result);
|
||||
for entry in WalkDir::new(&self.source)
|
||||
.follow_links(self.follow_links)
|
||||
.into_iter()
|
||||
{
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let path = Path::new(&path);
|
||||
|
||||
for mime_type in self.mime_types.iter() {
|
||||
if let Some(file_mime) = mime_guess::from_path(path).first() {
|
||||
if &file_mime == mime_type {
|
||||
let contents = Self::read_to_string(&path).unwrap();
|
||||
let hash = Self::hasher(&contents);
|
||||
let new_name = format!(
|
||||
"{}.{}.{}",
|
||||
path.file_stem().unwrap().to_str().unwrap(),
|
||||
hash,
|
||||
path.extension().unwrap().to_str().unwrap()
|
||||
);
|
||||
self.copy(path, &new_name);
|
||||
|
||||
let (source, destination) = self.gen_map(path, &&new_name);
|
||||
let _ = file_map.add(
|
||||
source.to_str().unwrap().into(),
|
||||
destination.to_str().unwrap().into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
file_map.to_env();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Processes files.
|
||||
///
|
||||
/// If MIME types are common, then use this funtion
|
||||
/// as it will panic when a weird MIM is encountered.
|
||||
/// Panics when a weird MIME is encountered.
|
||||
pub fn process(&self) -> Result<(), Error> {
|
||||
// panics when mimetypes are detected. This way you'll know which files are ignored
|
||||
// from processing
|
||||
|
@ -206,7 +159,7 @@ impl Buster {
|
|||
result = &self.result[1..];
|
||||
}
|
||||
let destination = Path::new(prefix)
|
||||
.join(&self.result[1..])
|
||||
.join(&result)
|
||||
.join(rel_location)
|
||||
.join(name);
|
||||
|
||||
|
@ -281,25 +234,33 @@ impl Files {
|
|||
/// This crate uses compile-time environment variables to transfer
|
||||
/// data to the main program. This funtction sets that variable
|
||||
fn to_env(&self) {
|
||||
println!(
|
||||
"cargo:rustc-env={}={}",
|
||||
ENV_VAR_NAME,
|
||||
serde_json::to_string(&self).unwrap()
|
||||
);
|
||||
let json = serde_json::to_string(&self).unwrap();
|
||||
// println!("cargo:rustc-env={}={}", ENV_VAR_NAME, json);
|
||||
let res = Path::new(CACHE_BUSTER_DATA_FILE);
|
||||
if res.exists() {
|
||||
fs::remove_file(&res).unwrap();
|
||||
}
|
||||
|
||||
// const PREFIX: &str = r##"pub const FILE_MAP: &str = r#" "##;
|
||||
// const POSTFIX: &str = r##""#;"##;
|
||||
|
||||
// let content = format!("#[allow(dead_code)]\n{}{}{}", &PREFIX, &json, &POSTFIX);
|
||||
|
||||
// fs::write(CACHE_BUSTER_DATA_FILE, content).unwrap();
|
||||
fs::write(CACHE_BUSTER_DATA_FILE, &json).unwrap();
|
||||
|
||||
// needed for testing load()
|
||||
// if the above statement fails(println), then something's broken
|
||||
// with the rust compiler. So not really worried about that.
|
||||
#[cfg(test)]
|
||||
std::env::set_var(ENV_VAR_NAME, serde_json::to_string(&self).unwrap());
|
||||
// #[cfg(test)]
|
||||
// std::env::set_var(ENV_VAR_NAME, serde_json::to_string(&self).unwrap());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Load filemap in main program. Should be called from main program
|
||||
fn load() -> Self {
|
||||
let env = std::env::var(ENV_VAR_NAME)
|
||||
.expect("unable to read env var, might be a bug in lib. Please report on GitHub");
|
||||
let res: Files = serde_json::from_str(&env).unwrap();
|
||||
let map = fs::read_to_string(CACHE_BUSTER_DATA_FILE).unwrap();
|
||||
let res: Files = serde_json::from_str(&map).unwrap();
|
||||
res
|
||||
}
|
||||
}
|
||||
|
@ -308,8 +269,8 @@ impl Files {
|
|||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hasher_works() {
|
||||
delete_file();
|
||||
let types = vec![
|
||||
mime::IMAGE_PNG,
|
||||
mime::IMAGE_SVG,
|
||||
|
@ -339,42 +300,17 @@ pub mod tests {
|
|||
cleanup(&config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_process_works() {
|
||||
let types = vec![
|
||||
mime::IMAGE_PNG,
|
||||
mime::IMAGE_SVG,
|
||||
mime::IMAGE_JPEG,
|
||||
mime::IMAGE_GIF,
|
||||
];
|
||||
|
||||
let config = BusterBuilder::default()
|
||||
.source("./dist")
|
||||
.result("/tmp/prod")
|
||||
.mime_types(types)
|
||||
.copy(true)
|
||||
.follow_links(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
config.process().unwrap();
|
||||
let mut files = Files::load();
|
||||
|
||||
for (k, v) in files.map.drain() {
|
||||
let src = Path::new(&k);
|
||||
let dest = Path::new(&v);
|
||||
|
||||
assert_eq!(src.exists(), dest.exists());
|
||||
}
|
||||
|
||||
cleanup(&config);
|
||||
}
|
||||
|
||||
pub fn cleanup(config: &Buster) {
|
||||
let _ = fs::remove_dir_all(&config.result);
|
||||
delete_file();
|
||||
}
|
||||
#[test]
|
||||
|
||||
pub fn delete_file() {
|
||||
let _ = fs::remove_file(&CACHE_BUSTER_DATA_FILE);
|
||||
}
|
||||
|
||||
fn prefix_works() {
|
||||
delete_file();
|
||||
let types = vec![
|
||||
mime::IMAGE_PNG,
|
||||
mime::IMAGE_SVG,
|
||||
|
@ -398,7 +334,6 @@ pub mod tests {
|
|||
if let Some(prefix) = &config.prefix {
|
||||
for (k, v) in files.map.drain() {
|
||||
let src = Path::new(&k);
|
||||
println!("{}", &v);
|
||||
let dest = Path::new(&v[prefix.len()..]);
|
||||
|
||||
assert_eq!(src.exists(), dest.exists());
|
||||
|
@ -407,4 +342,9 @@ pub mod tests {
|
|||
|
||||
cleanup(&config);
|
||||
}
|
||||
|
||||
pub fn runner() {
|
||||
prefix_works();
|
||||
hasher_works();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue