176 lines
5.6 KiB
Rust
176 lines
5.6 KiB
Rust
use pagetop_build::StaticFilesBundle;
|
|
|
|
use std::collections::HashMap;
|
|
use std::env;
|
|
use std::fs::{self, File};
|
|
use std::io::{self, BufRead, BufReader, Write};
|
|
use std::path::Path;
|
|
use std::process::Command;
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
|
const BUILD_STATE_FILE: &str = "./static/build_state.txt";
|
|
|
|
fn main() -> io::Result<()> {
|
|
// Reconstruye la documentación.
|
|
rebuild_doc()?;
|
|
|
|
// Crea la colección de archivos estáticos.
|
|
StaticFilesBundle::from_dir(
|
|
"./static/doc",
|
|
Some(pagetop_mdbook::build::except_common_resources),
|
|
)
|
|
.with_name("doc")
|
|
.build()
|
|
}
|
|
|
|
/// Reconstruye la documentación que ha cambiado para cada versión y sus idiomas.
|
|
fn rebuild_doc() -> io::Result<()> {
|
|
// Lee el estado de la última preparación.
|
|
let mut build_state = read_build_state()?;
|
|
|
|
// Define la ruta al directorio `doc`.
|
|
let project_dir = env::var("CARGO_MANIFEST_DIR").map_err(|e| {
|
|
io::Error::new(
|
|
io::ErrorKind::Other,
|
|
format!("Environment variable error: {}", e),
|
|
)
|
|
})?;
|
|
let doc_dir = Path::new(&project_dir).join("doc");
|
|
|
|
// Itera sobre las versiones de la documentación en `doc`.
|
|
for entry in fs::read_dir(&doc_dir)? {
|
|
let entry = entry?;
|
|
let version_dir = entry.path();
|
|
|
|
if version_dir.is_dir() && version_dir.file_name().unwrap_or_default() != "theme" {
|
|
let version_name = version_dir
|
|
.file_name()
|
|
.unwrap()
|
|
.to_string_lossy()
|
|
.to_string();
|
|
|
|
// Itera sobre los idiomas dentro de la versión.
|
|
for lang_entry in fs::read_dir(&version_dir)? {
|
|
let lang_entry = lang_entry?;
|
|
let lang_dir = lang_entry.path();
|
|
|
|
if lang_dir.is_dir() {
|
|
let lang_name = lang_dir.file_name().unwrap().to_string_lossy().to_string();
|
|
|
|
// Obtiene la última marca de tiempo de cambios en archivos para el idioma.
|
|
let latest_change_time = get_latest_change_time(&lang_dir)?;
|
|
|
|
// Obtiene la última marca de tiempo registrada para esta versión e idioma.
|
|
let state_key = format!("{}/{}", version_name, lang_name);
|
|
let last_build_time =
|
|
build_state.get(&state_key).copied().unwrap_or(UNIX_EPOCH);
|
|
|
|
// Si hay cambios, construye el libro para este idioma.
|
|
if latest_change_time > last_build_time {
|
|
build_mdbook(&lang_dir)?;
|
|
build_state.insert(state_key, SystemTime::now());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Guarda el estado actualizado.
|
|
write_build_state(&build_state)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Construye el libro mdBook para una versión específica.
|
|
fn build_mdbook(version_dir: &Path) -> io::Result<()> {
|
|
if !Command::new("mdbook")
|
|
.arg("build")
|
|
.current_dir(version_dir)
|
|
.status()?
|
|
.success()
|
|
{
|
|
return Err(io::Error::new(
|
|
io::ErrorKind::Other,
|
|
format!("Failed to build mdBook in {:?}", version_dir),
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Lee el estado de construcción desde un archivo de texto plano.
|
|
fn read_build_state() -> io::Result<HashMap<String, SystemTime>> {
|
|
let mut build_state = HashMap::new();
|
|
let path = Path::new(BUILD_STATE_FILE);
|
|
|
|
if path.exists() {
|
|
let file = File::open(path)?;
|
|
let reader = BufReader::new(file);
|
|
|
|
for line in reader.lines() {
|
|
let line = line?;
|
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
|
if parts.len() == 2 {
|
|
if let Ok(timestamp) = parts[1].parse::<u64>() {
|
|
build_state.insert(
|
|
parts[0].to_string(),
|
|
UNIX_EPOCH + std::time::Duration::from_secs(timestamp),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(build_state)
|
|
}
|
|
|
|
/// Escribe el estado de construcción en un archivo de texto plano.
|
|
fn write_build_state(build_state: &HashMap<String, SystemTime>) -> io::Result<()> {
|
|
let path = Path::new(BUILD_STATE_FILE);
|
|
|
|
// Crea el directorio `static` si no existe.
|
|
if let Some(parent) = path.parent() {
|
|
if !parent.exists() {
|
|
fs::create_dir_all(parent)?;
|
|
}
|
|
}
|
|
|
|
let mut file = File::create(path)?;
|
|
|
|
for (version, &time) in build_state {
|
|
let timestamp = time
|
|
.duration_since(UNIX_EPOCH)
|
|
.map_err(|e| {
|
|
io::Error::new(io::ErrorKind::Other, format!("Invalid system time: {}", e))
|
|
})?
|
|
.as_secs();
|
|
writeln!(file, "{} {}", version, timestamp)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Obtiene la marca de tiempo más reciente de los archivos de un directorio usando recursión.
|
|
fn get_latest_change_time(dir: &Path) -> io::Result<SystemTime> {
|
|
let mut latest = UNIX_EPOCH;
|
|
|
|
/// Función recursiva para recorrer directorios.
|
|
fn visit_dir(dir: &Path, latest: &mut SystemTime) -> io::Result<()> {
|
|
for entry in fs::read_dir(dir)? {
|
|
let entry = entry?;
|
|
let metadata = entry.metadata()?;
|
|
if metadata.is_dir() {
|
|
// Recurse en los subdirectorios.
|
|
visit_dir(&entry.path(), latest)?;
|
|
} else if let Ok(modified) = metadata.modified() {
|
|
// Actualiza la última marca de tiempo.
|
|
if modified > *latest {
|
|
*latest = modified;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
visit_dir(dir, &mut latest)?;
|
|
Ok(latest)
|
|
}
|