write filemap to file

This commit is contained in:
Aravinth Manivannan 2021-04-30 20:37:56 +05:30
parent d5593b2db6
commit 3c3b61aebf
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
9 changed files with 87 additions and 116 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ prod
tarpaulin-report.html
actix-example/target
actix-example/prod
prod56/

View file

@ -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
View file

@ -21,7 +21,7 @@ dependencies = [
[[package]]
name = "cache-buster"
version = "0.1.1"
version = "0.2.0"
dependencies = [
"data-encoding",
"derive_builder",

View file

@ -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"

File diff suppressed because one or more lines are too long

View file

@ -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(

View file

@ -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();
}
}

View file

@ -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";

View file

@ -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();
}
}