diff options
| author | Naz <ndpm13@ch-naseem.com> | 2025-10-11 14:44:12 +0100 |
|---|---|---|
| committer | Naz <ndpm13@ch-naseem.com> | 2025-10-12 09:54:00 +0100 |
| commit | bbce03f95d82d5373f2b6a1c28b03eb25d7bb94c (patch) | |
| tree | 7439ed8038bbb9a08a6b56fbfb90e8bea4b9f2ea | |
| parent | 50cf5960cb1f0af831e28eb08b15b97794287f87 (diff) | |
✨feat: add flags to override values in config file
| -rw-r--r-- | src/args.rs | 23 | ||||
| -rw-r--r-- | src/config.rs | 60 | ||||
| -rw-r--r-- | src/errors.rs | 8 | ||||
| -rw-r--r-- | src/lib.rs | 6 |
4 files changed, 79 insertions, 18 deletions
diff --git a/src/args.rs b/src/args.rs index 415d816..6998e15 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,4 +1,4 @@ -use clap::{Parser, Subcommand}; +use clap::{Args, Parser, Subcommand}; /// Simple bookmarks manager written in Rust #[derive(Debug, Parser)] @@ -12,5 +12,24 @@ pub struct Cli { pub enum Command { /// Start the web server to serve the bookmarks page #[command(name = "serv")] - Serv, + Serv(ServArgs), +} + +#[derive(Debug, Args)] +pub struct ServArgs { + // Port to listen to + #[arg(long = "port", short)] + pub port: Option<String>, + + // Path to theme file + #[arg(long = "style", short)] + pub style_file: Option<String>, + + // Path to bookmarks file + #[arg(long = "bookmarks", short)] + pub bookmarks_file: Option<String>, + + // Path to favicon file + #[arg(long = "favicon", short)] + pub favicon_file: Option<String>, } diff --git a/src/config.rs b/src/config.rs index 6345ffa..2f1bbb7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; -use crate::{Error, Result}; +use crate::{Error, Result, args::ServArgs}; const STYLE: &str = include_str!("../examples/simple-gruvbox.css"); const BOOKMARKS: &str = include_str!("../examples/bookmarks.json"); @@ -17,22 +17,20 @@ pub struct Config { } impl Config { - pub fn new() -> Result<Config> { - let config_home = if let Ok(xdg_config_home) = std::env::var("XDG_CONFIG_HOME") { - PathBuf::from(xdg_config_home).join("sbm-rs") - } else if let Ok(home) = std::env::var("HOME") { - PathBuf::from(home).join(".config/sbm-rs") + pub fn new(args: ServArgs) -> Result<Config> { + let config_home = Config::get_config_home()?; + + let config_path = &config_home.join("config.toml"); + + let mut config = if config_path.exists() { + Config::load_config(config_path)? } else { - return Err(Error::ConfigNotFound); + Config::generate_defaults(config_home)? }; - let config = &config_home.join("config.toml"); + config.override_with_serv_args(args)?; - if config.exists() { - Config::load_config(config) - } else { - Config::generate_defaults(config_home) - } + Ok(config) } pub fn load_config(config: &PathBuf) -> Result<Config> { let config = std::fs::read_to_string(&config)?; @@ -65,4 +63,40 @@ impl Config { Ok(config) } + pub fn override_with_serv_args(&mut self, args: ServArgs) -> Result<()> { + if let Some(port) = &args.port { + self.port = port.parse::<u16>()?; + } + + if let Some(style_file) = &args.style_file { + if PathBuf::from(style_file).exists() { + self.style_file = PathBuf::from(style_file) + } + } + + if let Some(bookmarks_file) = &args.bookmarks_file { + if PathBuf::from(bookmarks_file).exists() { + self.bookmarks_file = PathBuf::from(bookmarks_file) + } + } + + if let Some(favicon_file) = &args.favicon_file { + if PathBuf::from(favicon_file).exists() { + self.favicon_file = PathBuf::from(favicon_file) + } + } + + Ok(()) + } + fn get_config_home() -> Result<PathBuf> { + let config_home = if let Ok(xdg_config_home) = std::env::var("XDG_CONFIG_HOME") { + PathBuf::from(xdg_config_home).join("sbm-rs") + } else if let Ok(home) = std::env::var("HOME") { + PathBuf::from(home).join(".config/sbm-rs") + } else { + return Err(Error::ConfigHomeNotFound); + }; + + Ok(config_home) + } } diff --git a/src/errors.rs b/src/errors.rs index 251ee5f..6b53c2d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -28,6 +28,9 @@ pub enum Error { #[from] TomlSerError(toml::ser::Error), + + #[from] + ParseIntError(std::num::ParseIntError), } impl core::fmt::Display for Error { @@ -44,6 +47,7 @@ impl core::fmt::Display for Error { Error::SerdeError(e) => write!(fmt, "Serde error: {e}"), Error::TomlDeError(e) => write!(fmt, "TOML deserialization error: {e}"), Error::TomlSerError(e) => write!(fmt, "TOML serialization error: {e}"), + Error::ParseIntError(e) => write!(fmt, "Parsing error: {e}"), } } } @@ -80,6 +84,10 @@ impl IntoResponse for Error { StatusCode::INTERNAL_SERVER_ERROR, format!("TOML serialization error: {e}"), ), + Error::ParseIntError(ref e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Parsing error: {e}"), + ), }; println!("{} {}", &status, &error_message); @@ -27,10 +27,10 @@ pub fn app(config: Config) -> Router { pub async fn run() -> Result<()> { let args = Cli::parse(); - let config = config::Config::new()?; - match args.command { - Command::Serv => { + Command::Serv(args) => { + let config = config::Config::new(args)?; + let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), config.port); let listener = TcpListener::bind(socket).await?; |
