- Add `.gitignore` entries for `webmeta.json` and `.vscode` - Improve collection scanning logging for better debugging - Improve error handling in collection methods for robustness
162 lines
4.9 KiB
Rust
162 lines
4.9 KiB
Rust
use std::fs;
|
|
use std::path::Path;
|
|
|
|
use deser_hjson::from_str;
|
|
use serde::de::DeserializeOwned;
|
|
use serde_json::Value;
|
|
|
|
use crate::config::{
|
|
CollectionConfig, PageConfig, SiteConfig,
|
|
};
|
|
use crate::error::{Result, WebBuilderError};
|
|
|
|
/// Parse a hjson file into a struct
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `path` - Path to the hjson file
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// The parsed struct or an error
|
|
pub fn parse_hjson<T, P>(path: P) -> Result<T>
|
|
where
|
|
T: DeserializeOwned,
|
|
P: AsRef<Path>,
|
|
{
|
|
let path = path.as_ref();
|
|
|
|
// Check if the file exists
|
|
if !path.exists() {
|
|
return Err(WebBuilderError::MissingFile(path.to_path_buf()));
|
|
}
|
|
|
|
// Read the file
|
|
let content = fs::read_to_string(path).map_err(|e| WebBuilderError::IoError(e))?;
|
|
|
|
// Parse the hjson
|
|
from_str(&content).map_err(|e| WebBuilderError::HjsonError(format!("Error parsing {:?}: {}", path, e)))
|
|
}
|
|
|
|
/// Parse site configuration from a directory
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `path` - Path to the directory containing hjson configuration files
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// The parsed site configuration or an error
|
|
pub fn parse_site_config<P: AsRef<Path>>(path: P) -> Result<SiteConfig> {
|
|
let path = path.as_ref();
|
|
|
|
// Check if the directory exists
|
|
if !path.exists() {
|
|
return Err(WebBuilderError::MissingDirectory(path.to_path_buf()));
|
|
}
|
|
|
|
// Check if the directory is a directory
|
|
if !path.is_dir() {
|
|
return Err(WebBuilderError::InvalidConfiguration(format!(
|
|
"{:?} is not a directory",
|
|
path
|
|
)));
|
|
}
|
|
|
|
// Create a basic site configuration
|
|
let mut site_config = SiteConfig {
|
|
name: "default".to_string(),
|
|
title: "".to_string(),
|
|
description: None,
|
|
keywords: None,
|
|
url: None,
|
|
favicon: None,
|
|
header: None,
|
|
footer: None,
|
|
collections: Vec::new(),
|
|
pages: Vec::new(),
|
|
base_path: path.to_path_buf(),
|
|
};
|
|
|
|
// Parse main.hjson
|
|
let main_path = path.join("main.hjson");
|
|
if main_path.exists() {
|
|
let main_config: Value = parse_hjson(main_path)?;
|
|
|
|
// Extract values from main.hjson
|
|
if let Some(name) = main_config.get("name").and_then(|v| v.as_str()) {
|
|
site_config.name = name.to_string();
|
|
}
|
|
if let Some(title) = main_config.get("title").and_then(|v| v.as_str()) {
|
|
site_config.title = title.to_string();
|
|
}
|
|
if let Some(description) = main_config.get("description").and_then(|v| v.as_str()) {
|
|
site_config.description = Some(description.to_string());
|
|
}
|
|
if let Some(url) = main_config.get("url").and_then(|v| v.as_str()) {
|
|
site_config.url = Some(url.to_string());
|
|
}
|
|
if let Some(favicon) = main_config.get("favicon").and_then(|v| v.as_str()) {
|
|
site_config.favicon = Some(favicon.to_string());
|
|
}
|
|
if let Some(keywords) = main_config.get("keywords").and_then(|v| v.as_array()) {
|
|
let keywords_vec: Vec<String> = keywords
|
|
.iter()
|
|
.filter_map(|k| k.as_str().map(|s| s.to_string()))
|
|
.collect();
|
|
if !keywords_vec.is_empty() {
|
|
site_config.keywords = Some(keywords_vec);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse header.hjson
|
|
let header_path = path.join("header.hjson");
|
|
if header_path.exists() {
|
|
site_config.header = Some(parse_hjson(header_path)?);
|
|
}
|
|
|
|
// Parse footer.hjson
|
|
let footer_path = path.join("footer.hjson");
|
|
if footer_path.exists() {
|
|
site_config.footer = Some(parse_hjson(footer_path)?);
|
|
}
|
|
|
|
// Parse collection.hjson
|
|
let collection_path = path.join("collection.hjson");
|
|
if collection_path.exists() {
|
|
let collection_array: Vec<CollectionConfig> = parse_hjson(collection_path)?;
|
|
|
|
// Process each collection
|
|
for mut collection in collection_array {
|
|
// Convert web interface URL to Git URL if needed
|
|
if let Some(url) = &collection.url {
|
|
if url.contains("/src/branch/") {
|
|
// This is a web interface URL, convert it to a Git URL
|
|
let parts: Vec<&str> = url.split("/src/branch/").collect();
|
|
if parts.len() == 2 {
|
|
collection.url = Some(format!("{}.git", parts[0]));
|
|
}
|
|
}
|
|
}
|
|
site_config.collections.push(collection);
|
|
}
|
|
}
|
|
|
|
// Parse pages directory
|
|
let pages_path = path.join("pages");
|
|
if pages_path.exists() && pages_path.is_dir() {
|
|
for entry in fs::read_dir(pages_path)? {
|
|
let entry = entry?;
|
|
let entry_path = entry.path();
|
|
|
|
if entry_path.is_file() && entry_path.extension().map_or(false, |ext| ext == "hjson") {
|
|
let pages_array: Vec<PageConfig> = parse_hjson(&entry_path)?;
|
|
site_config.pages.extend(pages_array);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(site_config)
|
|
}
|