✨ Añade librería para gestionar recursos estáticos
This commit is contained in:
parent
8ed0e6621a
commit
4e277a2b03
20 changed files with 1370 additions and 41 deletions
249
helpers/pagetop-statics/src/resource.rs
Normal file
249
helpers/pagetop-statics/src/resource.rs
Normal file
|
@ -0,0 +1,249 @@
|
|||
use path_slash::PathExt;
|
||||
use std::{
|
||||
fs::{self, File, Metadata},
|
||||
io::{self, Write},
|
||||
path::{Path, PathBuf},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
/// Static files resource.
|
||||
pub struct Resource {
|
||||
pub data: &'static [u8],
|
||||
pub modified: u64,
|
||||
pub mime_type: &'static str,
|
||||
}
|
||||
|
||||
/// Used internally in generated functions.
|
||||
#[inline]
|
||||
pub fn new_resource(data: &'static [u8], modified: u64, mime_type: &'static str) -> Resource {
|
||||
Resource {
|
||||
data,
|
||||
modified,
|
||||
mime_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const DEFAULT_VARIABLE_NAME: &str = "r";
|
||||
|
||||
/// Generate resources for `project_dir` using `filter`.
|
||||
/// Result saved in `generated_filename` and function named as `fn_name`.
|
||||
///
|
||||
/// in `build.rs`:
|
||||
/// ```rust
|
||||
/// use std::{env, path::Path};
|
||||
/// use pagetop_statics::resource::generate_resources;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let out_dir = env::var("OUT_DIR").unwrap();
|
||||
/// let generated_filename = Path::new(&out_dir).join("generated.rs");
|
||||
/// generate_resources("./tests", None, generated_filename, "generate", "pagetop_statics").unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// in `main.rs`:
|
||||
/// ```rust
|
||||
/// include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||
///
|
||||
/// fn main() {
|
||||
/// let generated_file = generate();
|
||||
///
|
||||
/// assert_eq!(generated_file.len(), 4);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn generate_resources<P: AsRef<Path>, G: AsRef<Path>>(
|
||||
project_dir: P,
|
||||
filter: Option<fn(p: &Path) -> bool>,
|
||||
generated_filename: G,
|
||||
fn_name: &str,
|
||||
crate_name: &str,
|
||||
) -> io::Result<()> {
|
||||
let resources = collect_resources(&project_dir, filter)?;
|
||||
|
||||
let mut f = File::create(&generated_filename)?;
|
||||
|
||||
generate_function_header(&mut f, fn_name, crate_name)?;
|
||||
generate_uses(&mut f, crate_name)?;
|
||||
|
||||
generate_variable_header(&mut f, DEFAULT_VARIABLE_NAME)?;
|
||||
generate_resource_inserts(&mut f, &project_dir, DEFAULT_VARIABLE_NAME, resources)?;
|
||||
generate_variable_return(&mut f, DEFAULT_VARIABLE_NAME)?;
|
||||
|
||||
generate_function_end(&mut f)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generate resource mapping for `project_dir` using `filter`.
|
||||
/// Result saved in `generated_filename` as anonymous block which returns HashMap<&'static str, Resource>.
|
||||
///
|
||||
/// in `build.rs`:
|
||||
/// ```rust
|
||||
///
|
||||
/// use std::{env, path::Path};
|
||||
/// use pagetop_statics::resource::generate_resources_mapping;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let out_dir = env::var("OUT_DIR").unwrap();
|
||||
/// let generated_filename = Path::new(&out_dir).join("generated_mapping.rs");
|
||||
/// generate_resources_mapping("./tests", None, generated_filename, "pagetop_statics").unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// in `main.rs`:
|
||||
/// ```rust
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// use pagetop_statics::StaticResource;
|
||||
///
|
||||
/// fn generate_mapping() -> HashMap<&'static str, StaticResource> {
|
||||
/// include!(concat!(env!("OUT_DIR"), "/generated_mapping.rs"))
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let generated_file = generate_mapping();
|
||||
///
|
||||
/// assert_eq!(generated_file.len(), 4);
|
||||
///
|
||||
/// }
|
||||
/// ```
|
||||
pub fn generate_resources_mapping<P: AsRef<Path>, G: AsRef<Path>>(
|
||||
project_dir: P,
|
||||
filter: Option<fn(p: &Path) -> bool>,
|
||||
generated_filename: G,
|
||||
crate_name: &str,
|
||||
) -> io::Result<()> {
|
||||
let resources = collect_resources(&project_dir, filter)?;
|
||||
|
||||
let mut f = File::create(&generated_filename)?;
|
||||
writeln!(f, "{{")?;
|
||||
|
||||
generate_uses(&mut f, crate_name)?;
|
||||
|
||||
generate_variable_header(&mut f, DEFAULT_VARIABLE_NAME)?;
|
||||
|
||||
generate_resource_inserts(&mut f, &project_dir, DEFAULT_VARIABLE_NAME, resources)?;
|
||||
|
||||
generate_variable_return(&mut f, DEFAULT_VARIABLE_NAME)?;
|
||||
|
||||
writeln!(f, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sort"))]
|
||||
pub(crate) fn collect_resources<P: AsRef<Path>>(
|
||||
path: P,
|
||||
filter: Option<fn(p: &Path) -> bool>,
|
||||
) -> io::Result<Vec<(PathBuf, Metadata)>> {
|
||||
collect_resources_nested(path, filter)
|
||||
}
|
||||
|
||||
#[cfg(feature = "sort")]
|
||||
pub(crate) fn collect_resources<P: AsRef<Path>>(
|
||||
path: P,
|
||||
filter: Option<fn(p: &Path) -> bool>,
|
||||
) -> io::Result<Vec<(PathBuf, Metadata)>> {
|
||||
let mut resources = collect_resources_nested(path, filter)?;
|
||||
resources.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
Ok(resources)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_resources_nested<P: AsRef<Path>>(
|
||||
path: P,
|
||||
filter: Option<fn(p: &Path) -> bool>,
|
||||
) -> io::Result<Vec<(PathBuf, Metadata)>> {
|
||||
let mut result = vec![];
|
||||
|
||||
for entry in fs::read_dir(&path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(ref filter) = filter {
|
||||
if !filter(path.as_ref()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
let nested = collect_resources(path, filter)?;
|
||||
result.extend(nested);
|
||||
} else {
|
||||
result.push((path, entry.metadata()?));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_resource_inserts<P: AsRef<Path>, W: Write>(
|
||||
f: &mut W,
|
||||
project_dir: &P,
|
||||
variable_name: &str,
|
||||
resources: Vec<(PathBuf, Metadata)>,
|
||||
) -> io::Result<()> {
|
||||
for resource in &resources {
|
||||
generate_resource_insert(f, project_dir, variable_name, resource)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_debug_formatting)]
|
||||
pub(crate) fn generate_resource_insert<P: AsRef<Path>, W: Write>(
|
||||
f: &mut W,
|
||||
project_dir: &P,
|
||||
variable_name: &str,
|
||||
resource: &(PathBuf, Metadata),
|
||||
) -> io::Result<()> {
|
||||
let (path, metadata) = resource;
|
||||
let abs_path = path.canonicalize()?;
|
||||
let key_path = path.strip_prefix(project_dir).unwrap().to_slash().unwrap();
|
||||
|
||||
let modified = if let Ok(Ok(modified)) = metadata
|
||||
.modified()
|
||||
.map(|x| x.duration_since(SystemTime::UNIX_EPOCH))
|
||||
{
|
||||
modified.as_secs()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mime_type = mime_guess::MimeGuess::from_path(path).first_or_octet_stream();
|
||||
writeln!(
|
||||
f,
|
||||
"{}.insert({:?},n(i!({:?}),{:?},{:?}));",
|
||||
variable_name, &key_path, &abs_path, modified, &mime_type,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_function_header<F: Write>(
|
||||
f: &mut F,
|
||||
fn_name: &str,
|
||||
crate_name: &str,
|
||||
) -> io::Result<()> {
|
||||
writeln!(
|
||||
f,
|
||||
"#[allow(clippy::unreadable_literal)] pub fn {fn_name}() -> ::std::collections::HashMap<&'static str, ::{crate_name}::StaticResource> {{",
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_function_end<F: Write>(f: &mut F) -> io::Result<()> {
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
|
||||
pub(crate) fn generate_uses<F: Write>(f: &mut F, crate_name: &str) -> io::Result<()> {
|
||||
writeln!(
|
||||
f,
|
||||
"use ::{crate_name}::resource::new_resource as n;
|
||||
use ::std::include_bytes as i;",
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_variable_header<F: Write>(f: &mut F, variable_name: &str) -> io::Result<()> {
|
||||
writeln!(
|
||||
f,
|
||||
"let mut {variable_name} = ::std::collections::HashMap::new();",
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_variable_return<F: Write>(f: &mut F, variable_name: &str) -> io::Result<()> {
|
||||
writeln!(f, "{variable_name}")
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue