diff options
| author | Stanisław Zagórowski <hasohasacz@gmail.com> | 2024-01-11 16:23:45 +0100 |
|---|---|---|
| committer | Stanisław Zagórowski <hasohasacz@gmail.com> | 2024-01-11 16:23:45 +0100 |
| commit | f45abfdf2150d8136e3da48e1daba5473030c0be (patch) | |
| tree | a2dde05dd3577564bbdce51b847819d7ee12cc43 /src | |
| parent | 377a5a136d53bd91736a1dfbd418235d3b6b7462 (diff) | |
reorganize and prettify
Diffstat (limited to 'src')
| -rw-r--r-- | src/luax/mod.rs | 67 | ||||
| -rw-r--r-- | src/main.rs | 166 | ||||
| -rw-r--r-- | src/server.rs | 11 |
3 files changed, 166 insertions, 78 deletions
diff --git a/src/luax/mod.rs b/src/luax/mod.rs index df9f57d..2e6fe27 100644 --- a/src/luax/mod.rs +++ b/src/luax/mod.rs @@ -1,4 +1,4 @@ -use crate::Result; +use crate::{error::LuaXError, Result}; mod lexer; mod preprocessor; @@ -6,6 +6,63 @@ mod preprocessor; mod tests; mod tokens; +pub fn table_to_html<W: std::io::Write>(table: rlua::Table, f: &mut W) -> Result<()> { + let type_name: Option<String> = table.get("tag").unwrap(); + + if type_name.is_none() { + return Err(LuaXError::MissingField("tag".to_string()).into()); + } + + let type_name = type_name.unwrap(); + + write!(f, "<{}", type_name)?; + let mut children = None; + let mut attrs = None; + for pair in table.pairs::<String, rlua::Value>() { + let (key, value) = pair?; + if key == "tag" { + continue; + } + if key == "children" { + children = Some(value); + continue; + } + if key == "attrs" { + attrs = Some(value); + continue; + } + } + if let Some(attrs) = attrs { + if let rlua::Value::Table(attrs) = attrs { + for pair in attrs.pairs::<String, rlua::String>() { + let (key, value) = pair?; + write!(f, " {}=\"{}\"", key, value.to_str()?)?; + } + } else { + return Err(LuaXError::NonTableAttrs.into()); + } + } + write!(f, ">")?; + + if let Some(children) = children { + if let rlua::Value::Table(children) = children { + for child in children.sequence_values::<rlua::Value>() { + match child? { + rlua::Value::Table(child) => table_to_html(child, f)?, + rlua::Value::String(s) => write!(f, "{}", s.to_str()?)?, + _ => return Err(LuaXError::NonTableChildren.into()), + } + } + } else { + return Err(LuaXError::NonTableChildren.into()); + } + } + + write!(f, "</{}>", type_name)?; + + Ok(()) +} + pub fn preprocess(s: &str) -> Result<String> { let mut buf = Vec::new(); let preprocessor = preprocessor::Preprocessor::new(s, &mut buf)?; @@ -17,12 +74,13 @@ pub fn preprocess(s: &str) -> Result<String> { Ok(s) } -pub fn preprocess_dir(path: &std::path::Path) -> Result<()> { +pub fn preprocess_dir(path: &std::path::Path) -> Result<usize> { + let mut preprocessed = 0; for entry in std::fs::read_dir(path)? { let entry = entry?; let path = entry.path(); if path.is_dir() { - preprocess_dir(&path)?; + preprocessed += preprocess_dir(&path)?; } else { if path.extension().unwrap_or_default() != "luax" { continue; @@ -33,8 +91,9 @@ pub fn preprocess_dir(path: &std::path::Path) -> Result<()> { let out_path = path.with_extension("lua"); std::fs::write(out_path, s)?; + preprocessed += 1; } } - Ok(()) + Ok(preprocessed) } diff --git a/src/main.rs b/src/main.rs index 466ffbc..f4d06ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,76 +1,20 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use clap::Parser; -use color_eyre::Result; -use error::{LuaXError, ReluaxError}; +use color_eyre::{owo_colors::OwoColorize, Result}; mod error; mod luax; mod server; -fn table_to_html<W: std::io::Write>(table: rlua::Table, f: &mut W) -> Result<()> { - let type_name: Option<String> = table.get("tag").unwrap(); - - if type_name.is_none() { - return Err(ReluaxError::LuaX(LuaXError::MissingField("tag".to_string())).into()); - } - - let type_name = type_name.unwrap(); - - write!(f, "<{}", type_name)?; - let mut children = None; - let mut attrs = None; - for pair in table.pairs::<String, rlua::Value>() { - let (key, value) = pair?; - if key == "tag" { - continue; - } - if key == "children" { - children = Some(value); - continue; - } - if key == "attrs" { - attrs = Some(value); - continue; - } - } - if let Some(attrs) = attrs { - if let rlua::Value::Table(attrs) = attrs { - for pair in attrs.pairs::<String, rlua::String>() { - let (key, value) = pair?; - write!(f, " {}=\"{}\"", key, value.to_str()?)?; - } - } else { - return Err(ReluaxError::LuaX(LuaXError::NonTableAttrs).into()); - } - } - write!(f, ">")?; - - if let Some(children) = children { - if let rlua::Value::Table(children) = children { - for child in children.sequence_values::<rlua::Value>() { - match child? { - rlua::Value::Table(child) => table_to_html(child, f)?, - rlua::Value::String(s) => write!(f, "{}", s.to_str()?)?, - _ => return Err(ReluaxError::LuaX(LuaXError::NonTableChildren).into()), - } - } - } else { - return Err(ReluaxError::LuaX(LuaXError::NonTableChildren).into()); - } - } - - write!(f, "</{}>", type_name)?; - - Ok(()) -} - #[derive(Debug, Clone, clap::Parser)] struct Args { #[clap(short = 'C', long = "current-dir", default_value = ".")] current_dir: std::path::PathBuf, #[clap(short = 'p', long = "port", default_value = "4310")] port: u16, + #[clap(short = 'l', long = "local", default_value = "false")] + local: bool, } #[tokio::main] @@ -78,22 +22,86 @@ async fn main() -> color_eyre::Result<()> { color_eyre::install().unwrap(); let args = Args::parse(); - let current_dir = args.current_dir; + if !args.current_dir.is_dir() { + return Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("{} is not a directory", args.current_dir.display()), + ) + .into()); + } + + println!( + "🌴 Project root: {}", + args.current_dir.display().bright_yellow() + ); + + if args.local { + local(args).await + } else { + temp(args).await + } +} + +async fn local(args: Args) -> Result<()> { + println!("🌴 Running in local mode"); + std::env::set_current_dir(&args.current_dir)?; + preprocess_current_dir().await?; + + ensure_entry_point().await?; + + serve(args).await +} + +async fn temp(args: Args) -> Result<()> { + // Create a /tmp/reluax-XXXXXX directory for the server to pre-process files in. + let tmp_dir = tempfile::Builder::new() + .prefix("reluax-") + .tempdir() + .unwrap(); - if !current_dir.is_dir() { + if !tmp_dir.path().is_dir() { return Err(std::io::Error::new( std::io::ErrorKind::NotFound, - format!("{} is not a directory", current_dir.display()), + format!("{} is not a directory", tmp_dir.path().display()), ) .into()); } + println!( + "⏲️ Created temporary directory {}", + tmp_dir.path().display().bright_blue() + ); - std::env::set_current_dir(current_dir)?; + println!( + "⏲️ Will serve from {}", + tmp_dir.path().display().bright_blue() + ); + + // copy all files from the current directory to the temporary directory recursively. + let copied = recurse_copy(&args.current_dir, tmp_dir.path())?; + + println!("⏲️ {} files copied", copied.bright_green()); + + std::env::set_current_dir(tmp_dir.path())?; + + preprocess_current_dir().await?; + + ensure_entry_point().await?; + + serve(args).await +} - luax::preprocess_dir(std::env::current_dir()?.as_path())?; +async fn preprocess_current_dir() -> Result<()> { + let preprocessed = luax::preprocess_dir(std::env::current_dir()?.as_path())?; - println!("⛱️ Reluax files preprocessed!"); + println!( + "⛱️ {} Reluax files preprocessed!", + preprocessed.bright_green() + ); + Ok(()) +} + +async fn ensure_entry_point() -> Result<()> { let entry = PathBuf::from("reluax.lua"); if !entry.is_file() { @@ -104,7 +112,29 @@ async fn main() -> color_eyre::Result<()> { .into()); } - server::Server::serve(args.port).await?; - Ok(()) } + +async fn serve(args: Args) -> Result<()> { + server::Server::serve(args.port).await +} + +fn recurse_copy(from: &Path, to: &Path) -> Result<usize> { + let mut copied = 0; + for entry in std::fs::read_dir(from)? { + let entry = entry?; + let path = entry.path(); + let file_name = path.file_name().unwrap(); + let to = to.join(file_name); + + if path.is_dir() { + std::fs::create_dir(&to)?; + copied += recurse_copy(&path, &to)?; + } else { + std::fs::copy(&path, &to)?; + copied += 1; + } + } + + Ok(copied) +} diff --git a/src/server.rs b/src/server.rs index 4e3812f..106f9f8 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,10 +12,12 @@ use hyper_util::rt::TokioIo; use tokio::net::TcpListener; use crate::error::ReluaxError; -use crate::{table_to_html, Result}; +use crate::luax::table_to_html; +use color_eyre::Result; use rlua::Lua; pub struct Server { + port: u16, lua: Arc<Mutex<Lua>>, } @@ -23,20 +25,17 @@ struct State { lua: Arc<Mutex<Lua>>, } -static PORT: std::sync::OnceLock<u16> = std::sync::OnceLock::new(); - impl Server { pub async fn serve(port: u16) -> Result<()> { - PORT.set(port).unwrap(); - let server = Self { + port, lua: Arc::new(Mutex::new(Lua::new())), }; server.start().await } async fn start(self) -> Result<()> { - let addr = SocketAddr::from(([127, 0, 0, 1], *PORT.get().unwrap())); + let addr = SocketAddr::from(([127, 0, 0, 1], self.port)); let listener = TcpListener::bind(addr).await?; loop { |
