diff --git a/CHANGELOG.md b/CHANGELOG.md index ea397f0..fe3a935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `alt` tag to the git issue - by Awiteb - Add `description` tag to the patch - by Awiteb +### Refactor + +- Store the config in `CliOptions` instead of its path - by Awiteb + ## [0.2.0] - 2025-06-01 ### Added diff --git a/src/cli/commands/issue/new.rs b/src/cli/commands/issue/new.rs index b5d84d9..dbc0b67 100644 --- a/src/cli/commands/issue/new.rs +++ b/src/cli/commands/issue/new.rs @@ -21,7 +21,6 @@ use nostr::event::{EventBuilder, Tag}; use crate::{ cli::{ - CliConfig, CliOptions, CommandRunner, types::{NaddrOrSet, OptionNaddrOrSetVecExt, RelayOrSetVecExt}, @@ -97,12 +96,11 @@ impl NewArgs { impl CommandRunner for NewArgs { async fn run(self, options: CliOptions) -> N34Result<()> { - let config = CliConfig::load_toml(&options.config_path)?; let naddrs = utils::naddrs_or_file( - self.naddrs.flat_naddrs(&config.sets)?, + self.naddrs.flat_naddrs(&options.config.sets)?, &utils::nostr_address_path()?, )?; - let relays = options.relays.clone().flat_relays(&config.sets)?; + let relays = options.relays.clone().flat_relays(&options.config.sets)?; let client = NostrClient::init(&options, &relays).await; let user_pubk = options.pubkey().await?; let mut naddrs_iter = naddrs.clone().into_iter(); diff --git a/src/cli/commands/mod.rs b/src/cli/commands/mod.rs index 0042c6a..adf03d8 100644 --- a/src/cli/commands/mod.rs +++ b/src/cli/commands/mod.rs @@ -26,7 +26,6 @@ pub mod repo; pub mod sets; use std::fmt; -use std::path::PathBuf; use clap::{ArgGroup, Args, Parser}; use nostr::key::{Keys, PublicKey, SecretKey}; @@ -36,8 +35,9 @@ use self::patch::PatchSubcommands; use self::reply::ReplyArgs; use self::repo::RepoSubcommands; use self::sets::SetsSubcommands; -use super::traits::CommandRunner; +use super::CliConfig; use super::types::RelayOrSet; +use super::{parsers, traits::CommandRunner}; use crate::error::{N34Error, N34Result}; /// Default path used when no path is provided via command line arguments. @@ -58,19 +58,19 @@ pub const DEFAULT_FALLBACK_PATH: &str = "I_DO_NOT_KNOW_WHY_CLAP_DO_NOT_SUPPORT_L pub struct CliOptions { /// Your Nostr secret key #[arg(short, long)] - pub secret_key: Option, + pub secret_key: Option, /// Fallbacks relay to write and read from it. Multiple relays can be /// passed. #[arg(short, long)] - pub relays: Vec, + pub relays: Vec, /// Proof of Work difficulty when creatring events #[arg(long, default_value_t = 0)] - pub pow: u8, + pub pow: u8, /// Config path [default: `$XDG_CONFIG_HOME` or `$HOME/.config`] #[arg(long, value_name = "PATH", default_value = DEFAULT_FALLBACK_PATH, - hide_default_value = true + hide_default_value = true, value_parser = parsers::parse_config_path )] - pub config_path: PathBuf, + pub config: CliConfig, } /// N34 commands diff --git a/src/cli/commands/patch/send.rs b/src/cli/commands/patch/send.rs index b0e9c97..124293b 100644 --- a/src/cli/commands/patch/send.rs +++ b/src/cli/commands/patch/send.rs @@ -29,7 +29,6 @@ use nostr::{ use super::GitPatch; use crate::{ cli::{ - CliConfig, CliOptions, traits::CommandRunner, types::{NaddrOrSet, NostrEvent, OptionNaddrOrSetVecExt, RelayOrSetVecExt}, @@ -72,13 +71,12 @@ pub struct SendArgs { impl CommandRunner for SendArgs { async fn run(self, options: CliOptions) -> N34Result<()> { - let config = CliConfig::load_toml(&options.config_path)?; let naddrs = utils::naddrs_or_file( - self.naddrs.flat_naddrs(&config.sets)?, + self.naddrs.flat_naddrs(&options.config.sets)?, &utils::nostr_address_path()?, )?; let repo_coordinates = naddrs.clone().into_coordinates(); - let relays = options.relays.clone().flat_relays(&config.sets)?; + let relays = options.relays.clone().flat_relays(&options.config.sets)?; let user_pubk = options.pubkey().await?; let client = NostrClient::init(&options, &relays).await; diff --git a/src/cli/commands/reply.rs b/src/cli/commands/reply.rs index a5dd608..733868b 100644 --- a/src/cli/commands/reply.rs +++ b/src/cli/commands/reply.rs @@ -30,10 +30,7 @@ use nostr::{ use super::{CliOptions, CommandRunner}; use crate::{ - cli::{ - CliConfig, - types::{NaddrOrSet, NostrEvent, OptionNaddrOrSetVecExt, RelayOrSetVecExt}, - }, + cli::types::{NaddrOrSet, NostrEvent, OptionNaddrOrSetVecExt, RelayOrSetVecExt}, error::{N34Error, N34Result}, nostr_utils::{ NostrClient, @@ -84,12 +81,11 @@ pub struct ReplyArgs { impl CommandRunner for ReplyArgs { async fn run(self, options: CliOptions) -> N34Result<()> { let nostr_address_path = utils::nostr_address_path()?; - let config = CliConfig::load_toml(&options.config_path)?; - let relays = options.relays.clone().flat_relays(&config.sets)?; + let relays = options.relays.clone().flat_relays(&options.config.sets)?; let client = NostrClient::init(&options, &relays).await; let user_pubk = options.pubkey().await?; - let repo_naddrs = if let Some(naddrs) = self.naddrs.flat_naddrs(&config.sets)? { + let repo_naddrs = if let Some(naddrs) = self.naddrs.flat_naddrs(&options.config.sets)? { client.add_relays(&naddrs.extract_relays()).await; Some(naddrs) } else if fs::exists(&nostr_address_path).is_ok() { diff --git a/src/cli/commands/repo/announce.rs b/src/cli/commands/repo/announce.rs index 7c65030..150d8e7 100644 --- a/src/cli/commands/repo/announce.rs +++ b/src/cli/commands/repo/announce.rs @@ -21,7 +21,7 @@ use futures::future; use nostr::{event::EventBuilder, key::PublicKey, types::Url}; use crate::{ - cli::{CliConfig, CliOptions, CommandRunner, NOSTR_ADDRESS_FILE, types::RelayOrSetVecExt}, + cli::{CliOptions, CommandRunner, NOSTR_ADDRESS_FILE, types::RelayOrSetVecExt}, error::N34Result, nostr_utils::{NostrClient, traits::NewGitRepositoryAnnouncement, utils}, }; @@ -81,8 +81,7 @@ impl CommandRunner for AnnounceArgs { async fn run(mut self, options: CliOptions) -> N34Result<()> { options.ensure_relays()?; - let config = CliConfig::load_toml(&options.config_path)?; - let relays = options.relays.clone().flat_relays(&config.sets)?; + let relays = options.relays.clone().flat_relays(&options.config.sets)?; let client = NostrClient::init(&options, &relays).await; let user_pubk = options.pubkey().await?; let relays_list = client.user_relays_list(user_pubk).await?; diff --git a/src/cli/commands/repo/view.rs b/src/cli/commands/repo/view.rs index f8c4723..fff6e90 100644 --- a/src/cli/commands/repo/view.rs +++ b/src/cli/commands/repo/view.rs @@ -20,7 +20,6 @@ use clap::Args; use crate::{ cli::{ - CliConfig, CliOptions, CommandRunner, types::{NaddrOrSet, OptionNaddrOrSetVecExt, RelayOrSetVecExt}, @@ -44,12 +43,11 @@ impl CommandRunner for ViewArgs { async fn run(self, options: CliOptions) -> N34Result<()> { // FIXME: The signer is not required here - let config = CliConfig::load_toml(&options.config_path)?; let naddrs = utils::naddrs_or_file( - self.naddrs.flat_naddrs(&config.sets)?, + self.naddrs.flat_naddrs(&options.config.sets)?, &utils::nostr_address_path()?, )?; - let relays = options.relays.clone().flat_relays(&config.sets)?; + let relays = options.relays.clone().flat_relays(&options.config.sets)?; let client = NostrClient::init(&options, &relays).await; client.add_relays(&naddrs.extract_relays()).await; diff --git a/src/cli/commands/sets/new.rs b/src/cli/commands/sets/new.rs index 240e6cc..9640d0c 100644 --- a/src/cli/commands/sets/new.rs +++ b/src/cli/commands/sets/new.rs @@ -18,7 +18,6 @@ use clap::Args; use crate::{ cli::{ - CliConfig, CliOptions, ConfigError, MutRepoRelaySetsExt, @@ -44,16 +43,15 @@ pub struct NewArgs { impl CommandRunner for NewArgs { // FIXME: The signer is not required here - async fn run(self, options: CliOptions) -> N34Result<()> { - let mut config = CliConfig::load_toml(&options.config_path)?; - let naddrs = self.naddrs.flat_naddrs(&config.sets)?; - let relays = self.relays.flat_relays(&config.sets)?; + async fn run(self, mut options: CliOptions) -> N34Result<()> { + let naddrs = self.naddrs.flat_naddrs(&options.config.sets)?; + let relays = self.relays.flat_relays(&options.config.sets)?; if relays.is_empty() && naddrs.is_empty() { return Err(ConfigError::NewEmptySet.into()); } - config.sets.push_set(self.name, naddrs, relays)?; - config.dump_toml(&options.config_path) + options.config.sets.push_set(self.name, naddrs, relays)?; + options.config.dump_toml() } } diff --git a/src/cli/commands/sets/remove.rs b/src/cli/commands/sets/remove.rs index 3da6422..a1cd909 100644 --- a/src/cli/commands/sets/remove.rs +++ b/src/cli/commands/sets/remove.rs @@ -18,7 +18,6 @@ use clap::Args; use crate::{ cli::{ - CliConfig, CliOptions, MutRepoRelaySetsExt, traits::CommandRunner, @@ -44,22 +43,27 @@ pub struct RemoveArgs { impl CommandRunner for RemoveArgs { // FIXME: The signer is not required here - async fn run(self, options: CliOptions) -> N34Result<()> { - let mut config = CliConfig::load_toml(&options.config_path)?; - let naddrs = self.naddrs.flat_naddrs(&config.sets)?; - let relays = self.relays.flat_relays(&config.sets)?; + async fn run(self, mut options: CliOptions) -> N34Result<()> { + let naddrs = self.naddrs.flat_naddrs(&options.config.sets)?; + let relays = self.relays.flat_relays(&options.config.sets)?; if relays.is_empty() && naddrs.is_empty() { - config.sets.remove_set(self.name)?; + options.config.sets.remove_set(self.name)?; } else { if !relays.is_empty() { - config.sets.remove_relays(&self.name, relays.into_iter())?; + options + .config + .sets + .remove_relays(&self.name, relays.into_iter())?; } if !naddrs.is_empty() { - config.sets.remove_naddrs(self.name, naddrs.into_iter())?; + options + .config + .sets + .remove_naddrs(self.name, naddrs.into_iter())?; } } - config.dump_toml(&options.config_path) + options.config.dump_toml() } } diff --git a/src/cli/commands/sets/show.rs b/src/cli/commands/sets/show.rs index 9abbae8..bb51b88 100644 --- a/src/cli/commands/sets/show.rs +++ b/src/cli/commands/sets/show.rs @@ -18,7 +18,7 @@ use clap::Args; use nostr::nips::nip19::ToBech32; use crate::{ - cli::{CliConfig, CliOptions, RepoRelaySet, RepoRelaySetsExt, traits::CommandRunner}, + cli::{CliOptions, RepoRelaySet, RepoRelaySetsExt, traits::CommandRunner}, error::N34Result, }; @@ -31,14 +31,16 @@ pub struct ShowArgs { impl CommandRunner for ShowArgs { // FIXME: The signer is not required here async fn run(self, options: CliOptions) -> N34Result<()> { - let config = CliConfig::load_toml(&options.config_path)?; - if let Some(name) = self.name { - println!("{}", format_set(config.sets.as_slice().get_set(&name)?)); + println!( + "{}", + format_set(options.config.sets.as_slice().get_set(&name)?) + ); } else { println!( "{}", - config + options + .config .sets .iter() .map(format_set) diff --git a/src/cli/commands/sets/update.rs b/src/cli/commands/sets/update.rs index 4bfb36c..9368ce2 100644 --- a/src/cli/commands/sets/update.rs +++ b/src/cli/commands/sets/update.rs @@ -20,7 +20,6 @@ use clap::Args; use crate::{ cli::{ - CliConfig, CliOptions, MutRepoRelaySetsExt, traits::CommandRunner, @@ -48,12 +47,11 @@ pub struct UpdateArgs { impl CommandRunner for UpdateArgs { // FIXME: The signer is not required here - async fn run(self, options: CliOptions) -> N34Result<()> { - let mut config = CliConfig::load_toml(&options.config_path)?; - let naddrs = self.naddrs.flat_naddrs(&config.sets)?; - let relays = self.relays.flat_relays(&config.sets)?; + async fn run(self, mut options: CliOptions) -> N34Result<()> { + let naddrs = self.naddrs.flat_naddrs(&options.config.sets)?; + let relays = self.relays.flat_relays(&options.config.sets)?; - let set = config.sets.get_mut_set(&self.name)?; + let set = options.config.sets.get_mut_set(&self.name)?; if self.override_set { if !relays.is_empty() { @@ -67,6 +65,6 @@ impl CommandRunner for UpdateArgs { set.naddrs.extend(naddrs); } - config.dump_toml(&options.config_path) + options.config.dump_toml() } } diff --git a/src/cli/config.rs b/src/cli/config.rs index 6cff549..8eea84e 100644 --- a/src/cli/config.rs +++ b/src/cli/config.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::HashSet, fs, path::Path}; +use std::{collections::HashSet, fs, path::PathBuf}; use nostr::{ nips::nip19::{FromBech32, Nip19Coordinate, ToBech32}, @@ -51,6 +51,9 @@ pub enum ConfigError { /// Configuration for the command-line interface. #[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug)] pub struct CliConfig { + /// Path to the configuration file (not serialized) + #[serde(skip)] + path: PathBuf, /// Groups of repositories and relays. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub sets: Vec, @@ -77,7 +80,7 @@ pub struct RepoRelaySet { impl CliConfig { /// Reads and parse a TOML config file from the given path, creating it if /// missing. - pub fn load_toml(file_path: &Path) -> N34Result { + pub fn load_toml(file_path: PathBuf) -> N34Result { tracing::info!(path = %file_path.display(), "Loading configuration from file"); // Make sure the file is exist if let Some(parent) = file_path.parent() { @@ -85,11 +88,12 @@ impl CliConfig { fs::create_dir_all(parent)?; } } - let _ = fs::File::create_new(file_path); + let _ = fs::File::create_new(&file_path); let mut config: Self = - toml::from_str(&fs::read_to_string(file_path).map_err(ConfigError::ReadFile)?) + toml::from_str(&fs::read_to_string(&file_path).map_err(ConfigError::ReadFile)?) .map_err(ConfigError::ParseFile)?; + config.path = file_path; config.post_sets()?; @@ -97,12 +101,12 @@ impl CliConfig { } /// Dump the config as toml in a file - pub fn dump_toml(mut self, file_path: &Path) -> N34Result<()> { - tracing::debug!(config = ?self, "Writing configuration to {}", file_path.display()); + pub fn dump_toml(mut self) -> N34Result<()> { + tracing::debug!(config = ?self, "Writing configuration to {}", self.path.display()); self.post_sets()?; fs::write( - file_path, + &self.path, toml::to_string_pretty(&self).map_err(ConfigError::Serialize)?, ) .map_err(ConfigError::WriteFile)?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e1c6318..016f1b1 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -71,3 +71,9 @@ impl Cli { self.command.run(self.options).await } } + +/// Processes the CLI configuration and returns it if successful. +pub fn post_cli(cli: Cli) -> N34Result { + // TODO + Ok(cli) +} diff --git a/src/cli/parsers.rs b/src/cli/parsers.rs index 0d4d819..92070c0 100644 --- a/src/cli/parsers.rs +++ b/src/cli/parsers.rs @@ -14,14 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use nostr::{ Kind, nips::nip19::{FromBech32, Nip19Coordinate}, }; -use super::Cli; +use super::CliConfig; use crate::{ cli::DEFAULT_FALLBACK_PATH, error::{N34Error, N34Result}, @@ -55,11 +58,14 @@ pub fn parse_nostr_address_file(file_path: &Path) -> N34Result N34Result { - if let Some(DEFAULT_FALLBACK_PATH) = cli.options.config_path.to_str() { - cli.options.config_path = super::defaults::config_path()?; - } +/// Loads CLI configuration from given path. Uses default config path if input +/// matches fallback path. +pub fn parse_config_path(config_path: &str) -> N34Result { + let mut path = PathBuf::from(config_path.trim()); - Ok(cli) + if config_path == DEFAULT_FALLBACK_PATH { + path = super::defaults::config_path()?; + }; + + CliConfig::load_toml(path) } diff --git a/src/main.rs b/src/main.rs index 2f5bdb4..ff0dc97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,7 +61,7 @@ fn set_log_level(verbosity: Verbosity) { #[tokio::main] async fn main() -> ExitCode { - let cli = match cli::parsers::post_parse_cli(Cli::parse()) { + let cli = match cli::post_cli(Cli::parse()) { Ok(cli) => cli, Err(err) => { eprintln!("{err}");