#![allow(clippy::unwrap_used, clippy::expect_used)]
use anyhow::{Context, Result};
use dtt::datetime::DateTime;
use http_handle::Server;
use ssg::{cmd::SsgConfig, verify_and_copy_files, Paths};
use staticdatagen::compiler::service::compile;
use std::{
fs::{self, File},
io::Write,
path::PathBuf,
};
struct SiteGenerator {
config: SsgConfig,
paths: Paths,
log_file: File,
}
impl SiteGenerator {
fn new(site_name: &str, base_url: &str) -> Result<Self> {
let log_file = File::create("site_generation.log")
.context("Failed to create log file")?;
let base_dir = PathBuf::from("examples");
let content_dir = base_dir.join("content");
let output_dir = base_dir.join("build");
let template_dir = base_dir.join("templates");
let site_dir = base_dir.join("public");
fs::create_dir_all(&content_dir)
.context("Failed to create content directory")?;
fs::create_dir_all(&output_dir)
.context("Failed to create output directory")?;
fs::create_dir_all(&template_dir)
.context("Failed to create template directory")?;
let content_dir = fs::canonicalize(content_dir)?;
let output_dir = fs::canonicalize(output_dir)?;
let template_dir = fs::canonicalize(template_dir)?;
let site_dir = fs::canonicalize(site_dir.clone()).unwrap_or(site_dir);
let config = SsgConfig::builder()
.site_name(site_name.to_string())
.base_url(base_url.to_string())
.content_dir(content_dir.clone())
.output_dir(output_dir.clone())
.template_dir(template_dir.clone())
.site_title("Basic SSG Site".to_string())
.site_description("A basic static site built with SSG".to_string())
.language("en-GB".to_string())
.build()
.context("Failed to build configuration")?;
let paths = Paths {
content: content_dir,
build: output_dir,
site: site_dir,
template: template_dir,
};
Ok(Self {
config,
paths,
log_file,
})
}
fn prepare_directories(&self) -> Result<()> {
for (name, path) in [
("content", &self.config.content_dir),
("build", &self.config.output_dir),
("site", &self.paths.site),
("template", &self.config.template_dir),
] {
fs::create_dir_all(path).with_context(|| {
format!("Failed to create {} directory", name)
})?;
self.log_message(&format!(
"Ensured {} directory at: {}",
name,
path.display()
))?;
}
Ok(())
}
fn log_message(&self, message: &str) -> Result<()> {
let date = DateTime::new();
writeln!(&self.log_file, "[{}] INFO process: {}", date, message)
.context("Failed to write to log file")?;
println!("{}", message);
Ok(())
}
fn generate(&mut self) -> Result<()> {
self.log_message(&format!(
"Starting generation for site: {}",
self.config.site_name
))?;
self.prepare_directories()?;
self.log_message("Compiling site...")?;
compile(
&self.config.output_dir,
&self.config.content_dir,
&self.paths.site,
&self.config.template_dir,
)
.context("Failed to compile site")?;
self.log_message("Site compilation completed")?;
if !self.config.output_dir.exists() {
fs::create_dir_all(&self.config.output_dir)
.context("Failed to create build directory")?;
self.log_message(&format!(
"Created build directory at: {}",
self.config.output_dir.display()
))?;
}
self.log_message("Copying static files...")?;
verify_and_copy_files(&self.config.output_dir, &self.paths.site)
.context("Failed to copy static files")?;
self.log_message(&format!(
"Site generated successfully at: {}",
self.paths.site.display()
))?;
Ok(())
}
fn serve(&self) -> Result<()> {
self.log_message(
"Starting development server at http://127.0.0.1:3000",
)?;
let example_root: String = self
.paths
.site
.to_str()
.context("Failed to convert site path to string")?
.to_string();
let server = Server::new("127.0.0.1:3000", example_root.as_str());
let _ = server.start();
Ok(())
}
}
fn main() -> Result<()> {
let mut generator =
SiteGenerator::new("basic-site", "http://127.0.0.1:3000")?;
generator.generate()?;
generator.serve()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_site_generator_creation() -> Result<()> {
let generator = SiteGenerator::new("test-site", "127.0.0.1:3000")?;
assert_eq!(generator.config.site_name, "test-site");
assert_eq!(generator.config.base_url, "127.0.0.1:3000");
Ok(())
}
#[test]
fn test_directory_preparation() -> Result<()> {
let generator = SiteGenerator::new("test-site", "127.0.0.1:3000")?;
generator.prepare_directories()?;
assert!(generator.config.content_dir.exists());
assert!(generator.config.output_dir.exists());
assert!(generator.config.template_dir.exists());
assert!(generator.paths.site.exists());
Ok(())
}
}