mod server;
mod watcher;
use std::path::Path;
use tokio::sync::mpsc;
use crate::proc::context_from_toml;
use crate::tool::DEFAULT_CONFIG_FILE;
use crate::tool::kits;
use crate::tool::procs::{BuildConfig, build_assets};
pub async fn run(port: u16, profile: Option<&str>) -> std::io::Result<()> {
let config_path = Path::new(DEFAULT_CONFIG_FILE);
let loaded = crate::tool::load_config(config_path, profile).await?;
let config = loaded.profile;
let source_path = config.paths.source.as_ref().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"missing paths.source in config",
)
})?;
let target_path = config.paths.target.as_ref().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"missing paths.target in config",
)
})?;
let source = Path::new(source_path).to_path_buf();
let target = Path::new(target_path).to_path_buf();
let clean_urls = config.paths.clean_urls.unwrap_or(false);
let resolved_kits = kits::resolve_kits(&loaded.kits, &loaded.config_dir).await?;
let project_root = loaded.config_dir;
let build_config = BuildConfig {
source: &source,
target: &target,
procs: &config.procs,
tools: &config.tools,
clean_urls,
resolved_kits: &resolved_kits,
project_root: &project_root,
};
tracing::info!("Running initial build...");
build(&build_config, &config.context).await?;
let (rebuild_tx, mut rebuild_rx) = mpsc::channel::<()>(1);
let watcher_source = source.clone();
let _watcher = watcher::start(&watcher_source, rebuild_tx)?;
tracing::info!("Watching {} for changes", source.display());
let server_target = target.clone();
let server_handle = tokio::spawn(async move {
if let Err(e) = server::start(port, &server_target).await {
tracing::error!("Server error: {}", e);
}
});
tracing::info!("Server running at http://localhost:{}", port);
while rebuild_rx.recv().await.is_some() {
tracing::info!("Change detected, rebuilding...");
match build(&build_config, &config.context).await {
Ok(()) => tracing::info!("Rebuild complete"),
Err(e) => tracing::error!("Rebuild failed: {}", e),
}
}
let _ = server_handle.await;
Ok(())
}
async fn build(config: &BuildConfig<'_>, context_values: &toml::Table) -> std::io::Result<()> {
let mut context = context_from_toml(context_values.clone()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("invalid context value: {:?}", e),
)
})?;
build_assets(config, &mut context).await
}