From 2040854e82c0980df1e8c20d34eb6533b5240d2a Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 14 Dec 2025 15:08:55 -0300 Subject: [PATCH] Handle CLI arguments as structured argument-parameter pairs --- .justfile | 4 +-- src/formats.rs | 8 ++++-- src/handlers/fixed.rs | 4 ++- src/handlers/graph.rs | 8 ++---- src/main.rs | 10 +++---- src/syntax.rs | 1 + src/syntax/arguments.rs | 63 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 src/syntax.rs create mode 100644 src/syntax/arguments.rs diff --git a/.justfile b/.justfile index f34bf85..19b6f7f 100644 --- a/.justfile +++ b/.justfile @@ -6,7 +6,7 @@ _default: # Build on changes [group('dev')] serve-watch: - bacon --job run-long -- localhost:3003 + bacon --job run-long -- -- --host localhost --port 3003 alias sw := serve-watch alias dev := serve-watch @@ -37,7 +37,7 @@ push: check # Start server [group('run')] serve: - cargo run localhost:3003 + cargo run -- --hostname localhost --port 3003 alias s := serve diff --git a/src/formats.rs b/src/formats.rs index 2054962..28eff67 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -1,9 +1,13 @@ use std::collections::HashMap; -use crate::types::{Graph, Node, Edge}; +use crate::{ + syntax::arguments::Arguments, + types::{Edge, Graph, Node}, +}; pub fn populate_graph() -> Graph { - let toml_source = match std::fs::read_to_string("./static/graph.toml") { + let args = Arguments::new().parse(); + let toml_source = match std::fs::read_to_string(args.graph_path) { Ok(s) => s, Err(e) => format!("Error: {e}"), }; diff --git a/src/handlers/fixed.rs b/src/handlers/fixed.rs index c9b0fb0..a74093c 100644 --- a/src/handlers/fixed.rs +++ b/src/handlers/fixed.rs @@ -3,7 +3,9 @@ use axum::{ http::{Response, StatusCode, header, HeaderValue}, }; -use crate::formats::{Format, populate_graph, serialize_graph}; +use crate::{ + formats::{Format, populate_graph, serialize_graph}, +}; use crate::handlers; pub async fn file(file_path: &str, content_type: &str) -> Response { diff --git a/src/handlers/graph.rs b/src/handlers/graph.rs index dfabf82..8b16b69 100644 --- a/src/handlers/graph.rs +++ b/src/handlers/graph.rs @@ -1,16 +1,14 @@ use axum::{body::Body, extract::Path, http::Response}; -use crate::{formats::populate_graph, types::Node, handlers}; +use crate::{formats::populate_graph, handlers, types::Node}; pub async fn node(Path(id): Path) -> Response { let mut context = tera::Context::new(); let graph = populate_graph(); - let nodes = graph.nodes; - let empty_node = - Node::new(Some(format!("Could not find node with ID {id}."))); + let empty_node = Node::new(Some(format!("Could not find node ID {id}."))); - let node: &Node = nodes.get(&id).unwrap_or(&empty_node); + let node: &Node = graph.nodes.get(&id).unwrap_or(&empty_node); context.insert("id", &id); context.insert("title", &node.title); diff --git a/src/main.rs b/src/main.rs index edeb0c7..1d637e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{backtrace, env, io, panic, sync, time}; +use std::{backtrace, io, panic, sync, time}; use axum::{routing::get, Router}; @@ -7,6 +7,7 @@ use formats::Format; mod formats; mod types; mod handlers; +mod syntax; mod dev; static ONSET: sync::LazyLock = @@ -14,9 +15,8 @@ static ONSET: sync::LazyLock = #[tokio::main] async fn main() -> io::Result<()> { - let args: Vec = env::args().collect(); - let default_address = "0.0.0.0:0".to_string(); - let address: &String = args.get(1).unwrap_or(&default_address); + let args = syntax::arguments::Arguments::new().parse(); + let address = args.make_address(); panic::set_hook(Box::new(|info| { let payload = info @@ -73,7 +73,7 @@ async fn main() -> io::Result<()> { .fallback(handlers::error::not_found); let listener = - tokio::net::TcpListener::bind(address).await.map_err(|e| { + tokio::net::TcpListener::bind(&address).await.map_err(|e| { dev::log( &main, &format!("Failed to create listener at {address}: {e:#?}"), diff --git a/src/syntax.rs b/src/syntax.rs new file mode 100644 index 0000000..d08cc22 --- /dev/null +++ b/src/syntax.rs @@ -0,0 +1 @@ +pub mod arguments; diff --git a/src/syntax/arguments.rs b/src/syntax/arguments.rs new file mode 100644 index 0000000..4226474 --- /dev/null +++ b/src/syntax/arguments.rs @@ -0,0 +1,63 @@ +use std::path::PathBuf; + +#[derive(Clone, Debug)] +pub struct Arguments { + pub hostname: String, + pub port: u16, + pub graph_path: PathBuf, +} + +impl Arguments { + pub fn make_address(&self) -> String { + format!("{}:{}", self.hostname, self.port) + } + + pub fn new() -> Arguments { + Arguments { + hostname: String::from("0.0.0.0"), + port: 0, + graph_path: PathBuf::from("./static/graph.toml"), + } + } + + pub fn parse(&self) -> Arguments { + let args: Vec = std::env::args().collect(); + parse(self, &args) + } +} + +fn parse(defaults: &Arguments, args: &[String]) -> Arguments { + let mut out_args = defaults.clone(); + + let filtered_args = if let Some((head, tail)) = args.split_first() { + if head.starts_with('-') { args } else { tail } + } else { + args + }; + + for arg in filtered_args.chunks(2) { + if let Some(argument) = arg.first() + && let Some(parameter) = arg.last() + { + if argument.eq("-h") || argument.eq("--hostname") { + out_args.hostname = String::from(parameter); + } else if argument.eq("-p") || argument.eq("--port") { + out_args.port = parameter.parse().unwrap_or(out_args.port); + } else if argument.eq("-g") || argument.eq("--graph") { + out_args.graph_path = PathBuf::from(parameter); + } else { + crate::dev::log( + &parse, + &format!("Dropped unrecognized argument {argument}"), + ); + } + } else { + crate::dev::log( + &parse, + "Dropped: Couldn't pair either one of or + both argument \"{argument}\", parameter \"{parameter}\"", + ); + } + } + out_args +}