184 lines
4.9 KiB
Rust
184 lines
4.9 KiB
Rust
use std::{
|
|
fs::{self, File, Metadata},
|
|
io::{self, Write},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use super::resource::{
|
|
collect_resources, generate_function_end, generate_function_header, generate_resource_insert,
|
|
generate_uses, generate_variable_header, generate_variable_return, DEFAULT_VARIABLE_NAME,
|
|
};
|
|
|
|
/// Defines the split strategie.
|
|
pub trait SetSplitStrategie {
|
|
/// Register next file from resources.
|
|
fn register(&mut self, path: &Path, metadata: &Metadata);
|
|
/// Determine, should we split modules now.
|
|
fn should_split(&self) -> bool;
|
|
/// Resets internal counters after split.
|
|
fn reset(&mut self);
|
|
}
|
|
|
|
/// Split modules by files count.
|
|
pub struct SplitByCount {
|
|
current: usize,
|
|
max: usize,
|
|
}
|
|
|
|
impl SplitByCount {
|
|
pub fn new(max: usize) -> Self {
|
|
Self { current: 0, max }
|
|
}
|
|
}
|
|
|
|
impl SetSplitStrategie for SplitByCount {
|
|
fn register(&mut self, _path: &Path, _metadata: &Metadata) {
|
|
self.current += 1;
|
|
}
|
|
|
|
fn should_split(&self) -> bool {
|
|
self.current >= self.max
|
|
}
|
|
|
|
fn reset(&mut self) {
|
|
self.current = 0;
|
|
}
|
|
}
|
|
|
|
/// Generate resources for `project_dir` using `filter`
|
|
/// breaking them into separate modules using `set_split_strategie` (recommended for large > 128 Mb setups).
|
|
///
|
|
/// Result saved in module named `module_name`. It exports
|
|
/// only one function named `fn_name`. It is then exported from
|
|
/// `generated_filename`. `generated_filename` is also used to determine
|
|
/// the parent directory for the module.
|
|
///
|
|
/// in `build.rs`:
|
|
/// ```rust
|
|
///
|
|
/// use std::{env, path::Path};
|
|
/// use pagetop_statics::sets::{generate_resources_sets, SplitByCount};
|
|
///
|
|
/// fn main() {
|
|
/// let out_dir = env::var("OUT_DIR").unwrap();
|
|
/// let generated_filename = Path::new(&out_dir).join("generated_sets.rs");
|
|
/// generate_resources_sets(
|
|
/// "./tests",
|
|
/// None,
|
|
/// generated_filename,
|
|
/// "sets",
|
|
/// "generate",
|
|
/// &mut SplitByCount::new(2),
|
|
/// "pagetop_statics",
|
|
/// )
|
|
/// .unwrap();
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// in `main.rs`:
|
|
/// ```rust
|
|
/// include!(concat!(env!("OUT_DIR"), "/generated_sets.rs"));
|
|
///
|
|
/// fn main() {
|
|
/// let generated_file = generate();
|
|
///
|
|
/// assert_eq!(generated_file.len(), 4);
|
|
///
|
|
/// }
|
|
/// ```
|
|
pub fn generate_resources_sets<P, G, S>(
|
|
project_dir: P,
|
|
filter: Option<fn(p: &Path) -> bool>,
|
|
generated_filename: G,
|
|
module_name: &str,
|
|
fn_name: &str,
|
|
set_split_strategie: &mut S,
|
|
crate_name: &str,
|
|
) -> io::Result<()>
|
|
where
|
|
P: AsRef<Path>,
|
|
G: AsRef<Path>,
|
|
S: SetSplitStrategie,
|
|
{
|
|
let resources = collect_resources(&project_dir, filter)?;
|
|
|
|
let mut generated_file = File::create(&generated_filename)?;
|
|
|
|
let module_dir = generated_filename.as_ref().parent().map_or_else(
|
|
|| PathBuf::from(module_name),
|
|
|parent| parent.join(module_name),
|
|
);
|
|
fs::create_dir_all(&module_dir)?;
|
|
|
|
let mut module_file = File::create(module_dir.join("mod.rs"))?;
|
|
|
|
generate_uses(&mut module_file, crate_name)?;
|
|
writeln!(
|
|
module_file,
|
|
"
|
|
use ::{crate_name}::StaticResource;
|
|
use ::std::collections::HashMap;"
|
|
)?;
|
|
|
|
let mut modules_count = 1;
|
|
|
|
let mut set_file = create_set_module_file(&module_dir, modules_count)?;
|
|
let mut should_split = set_split_strategie.should_split();
|
|
|
|
for resource in &resources {
|
|
let (path, metadata) = &resource;
|
|
if should_split {
|
|
set_split_strategie.reset();
|
|
modules_count += 1;
|
|
generate_function_end(&mut set_file)?;
|
|
set_file = create_set_module_file(&module_dir, modules_count)?;
|
|
}
|
|
set_split_strategie.register(path, metadata);
|
|
should_split = set_split_strategie.should_split();
|
|
|
|
generate_resource_insert(&mut set_file, &project_dir, DEFAULT_VARIABLE_NAME, resource)?;
|
|
}
|
|
|
|
generate_function_end(&mut set_file)?;
|
|
|
|
for module_index in 1..=modules_count {
|
|
writeln!(module_file, "mod set_{module_index};")?;
|
|
}
|
|
|
|
generate_function_header(&mut module_file, fn_name, crate_name)?;
|
|
|
|
generate_variable_header(&mut module_file, DEFAULT_VARIABLE_NAME)?;
|
|
|
|
for module_index in 1..=modules_count {
|
|
writeln!(
|
|
module_file,
|
|
"set_{module_index}::generate(&mut {DEFAULT_VARIABLE_NAME});",
|
|
)?;
|
|
}
|
|
|
|
generate_variable_return(&mut module_file, DEFAULT_VARIABLE_NAME)?;
|
|
|
|
generate_function_end(&mut module_file)?;
|
|
|
|
writeln!(
|
|
generated_file,
|
|
"mod {module_name};
|
|
pub use {module_name}::{fn_name};",
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn create_set_module_file(module_dir: &Path, module_index: usize) -> io::Result<File> {
|
|
let mut set_module = File::create(module_dir.join(format!("set_{module_index}.rs")))?;
|
|
|
|
writeln!(
|
|
set_module,
|
|
"#[allow(clippy::wildcard_imports)]
|
|
use super::*;
|
|
#[allow(clippy::unreadable_literal)]
|
|
pub(crate) fn generate({DEFAULT_VARIABLE_NAME}: &mut HashMap<&'static str, StaticResource>) {{",
|
|
)?;
|
|
|
|
Ok(set_module)
|
|
}
|