diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-10 12:51:45 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-10 13:03:31 +0000 |
| commit | 9d142ee7046a415bb764f626e61476ed349c98ca (patch) | |
| tree | 11b91693428055590ed44c7c180f2a985a8ac944 /src | |
| parent | d2412565334f48bd31e57d29d7959c24258ccd98 (diff) | |
feat: add global CLI flags for non-interactive mode
Add --defaults, --interactive, and --force flags to support non-interactive
operation. Non-interactive mode is now the default behavior, with interactive
mode enabled via the -i/--interactive flag.
Also add CliError handling in main() to support styled error output from
subcommands.
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/ngit/cli.rs | 12 | ||||
| -rw-r--r-- | src/bin/ngit/main.rs | 26 |
2 files changed, 34 insertions, 4 deletions
diff --git a/src/bin/ngit/cli.rs b/src/bin/ngit/cli.rs index 76874c3..d2246d7 100644 --- a/src/bin/ngit/cli.rs +++ b/src/bin/ngit/cli.rs | |||
| @@ -11,6 +11,7 @@ use crate::sub_commands; | |||
| 11 | help_template = "{name} {version}\nnostr plugin for git\n - clone a nostr repository, or add as a remote, by using the url format nostr://pub123/identifier\n - remote branches beginning with `pr/` are open PRs from contributors; `ngit list` can be used to view all PRs\n - to open a PR, push a branch with the prefix `pr/` or use `ngit send` for advanced options\n- publish a repository to nostr with `ngit init`\n\n{usage}\n{all-args}" | 11 | help_template = "{name} {version}\nnostr plugin for git\n - clone a nostr repository, or add as a remote, by using the url format nostr://pub123/identifier\n - remote branches beginning with `pr/` are open PRs from contributors; `ngit list` can be used to view all PRs\n - to open a PR, push a branch with the prefix `pr/` or use `ngit send` for advanced options\n- publish a repository to nostr with `ngit init`\n\n{usage}\n{all-args}" |
| 12 | )] | 12 | )] |
| 13 | #[command(propagate_version = true)] | 13 | #[command(propagate_version = true)] |
| 14 | #[allow(clippy::struct_excessive_bools)] | ||
| 14 | pub struct Cli { | 15 | pub struct Cli { |
| 15 | #[command(subcommand)] | 16 | #[command(subcommand)] |
| 16 | pub command: Option<Commands>, | 17 | pub command: Option<Commands>, |
| @@ -32,6 +33,15 @@ pub struct Cli { | |||
| 32 | /// show customization options via git config | 33 | /// show customization options via git config |
| 33 | #[arg(short, long, global = true)] | 34 | #[arg(short, long, global = true)] |
| 34 | pub customize: bool, | 35 | pub customize: bool, |
| 36 | /// Use default values without prompting (non-interactive mode) | ||
| 37 | #[arg(short = 'd', long, global = true, conflicts_with = "interactive")] | ||
| 38 | pub defaults: bool, | ||
| 39 | /// Enable interactive prompts (default behavior) | ||
| 40 | #[arg(short = 'i', long, global = true)] | ||
| 41 | pub interactive: bool, | ||
| 42 | /// Force operations, bypass safety guards | ||
| 43 | #[arg(short = 'f', long, global = true)] | ||
| 44 | pub force: bool, | ||
| 35 | } | 45 | } |
| 36 | 46 | ||
| 37 | pub const CUSTOMISE_TEMPLATE: &str = r" | 47 | pub const CUSTOMISE_TEMPLATE: &str = r" |
| @@ -111,6 +121,8 @@ pub enum AccountCommands { | |||
| 111 | Logout, | 121 | Logout, |
| 112 | /// export nostr keys to login to other nostr clients | 122 | /// export nostr keys to login to other nostr clients |
| 113 | ExportKeys, | 123 | ExportKeys, |
| 124 | /// create a new nostr account | ||
| 125 | Create(sub_commands::create::SubCommandArgs), | ||
| 114 | } | 126 | } |
| 115 | 127 | ||
| 116 | #[derive(clap::Parser)] | 128 | #[derive(clap::Parser)] |
diff --git a/src/bin/ngit/main.rs b/src/bin/ngit/main.rs index 71b6e85..5d29b02 100644 --- a/src/bin/ngit/main.rs +++ b/src/bin/ngit/main.rs | |||
| @@ -2,13 +2,13 @@ | |||
| 2 | #![allow(clippy::large_futures)] | 2 | #![allow(clippy::large_futures)] |
| 3 | #![cfg_attr(not(test), warn(clippy::expect_used))] | 3 | #![cfg_attr(not(test), warn(clippy::expect_used))] |
| 4 | 4 | ||
| 5 | use anyhow::Result; | ||
| 6 | use clap::Parser; | 5 | use clap::Parser; |
| 7 | use cli::{AccountCommands, CUSTOMISE_TEMPLATE, Cli, Commands}; | 6 | use cli::{AccountCommands, CUSTOMISE_TEMPLATE, Cli, Commands}; |
| 8 | 7 | ||
| 9 | mod cli; | 8 | mod cli; |
| 10 | use ngit::{ | 9 | use ngit::{ |
| 11 | cli_interactor, client, | 10 | cli_interactor::{self, CliError}, |
| 11 | client, | ||
| 12 | git::{self, utils::set_git_timeout}, | 12 | git::{self, utils::set_git_timeout}, |
| 13 | git_events, login, repo_ref, | 13 | git_events, login, repo_ref, |
| 14 | }; | 14 | }; |
| @@ -16,9 +16,15 @@ use ngit::{ | |||
| 16 | mod sub_commands; | 16 | mod sub_commands; |
| 17 | 17 | ||
| 18 | #[tokio::main] | 18 | #[tokio::main] |
| 19 | async fn main() -> Result<()> { | 19 | async fn main() { |
| 20 | let cli = Cli::parse(); | 20 | let cli = Cli::parse(); |
| 21 | 21 | ||
| 22 | // Non-interactive by default; set NGIT_INTERACTIVE_MODE only when -i is | ||
| 23 | // specified | ||
| 24 | if cli.interactive { | ||
| 25 | std::env::set_var("NGIT_INTERACTIVE_MODE", "1"); | ||
| 26 | } | ||
| 27 | |||
| 22 | if cli.customize { | 28 | if cli.customize { |
| 23 | print!("{CUSTOMISE_TEMPLATE}"); | 29 | print!("{CUSTOMISE_TEMPLATE}"); |
| 24 | std::process::exit(0); // Exit the program | 30 | std::process::exit(0); // Exit the program |
| @@ -26,7 +32,7 @@ async fn main() -> Result<()> { | |||
| 26 | 32 | ||
| 27 | let _ = set_git_timeout(); | 33 | let _ = set_git_timeout(); |
| 28 | 34 | ||
| 29 | if let Some(command) = &cli.command { | 35 | let result = if let Some(command) = &cli.command { |
| 30 | match command { | 36 | match command { |
| 31 | Commands::Account(args) => match &args.account_command { | 37 | Commands::Account(args) => match &args.account_command { |
| 32 | AccountCommands::Login(sub_args) => { | 38 | AccountCommands::Login(sub_args) => { |
| @@ -34,6 +40,9 @@ async fn main() -> Result<()> { | |||
| 34 | } | 40 | } |
| 35 | AccountCommands::Logout => sub_commands::logout::launch().await, | 41 | AccountCommands::Logout => sub_commands::logout::launch().await, |
| 36 | AccountCommands::ExportKeys => sub_commands::export_keys::launch().await, | 42 | AccountCommands::ExportKeys => sub_commands::export_keys::launch().await, |
| 43 | AccountCommands::Create(sub_args) => { | ||
| 44 | sub_commands::create::launch(&cli, sub_args).await | ||
| 45 | } | ||
| 37 | }, | 46 | }, |
| 38 | Commands::Init(args) => sub_commands::init::launch(&cli, args).await, | 47 | Commands::Init(args) => sub_commands::init::launch(&cli, args).await, |
| 39 | Commands::List => sub_commands::list::launch().await, | 48 | Commands::List => sub_commands::list::launch().await, |
| @@ -44,5 +53,14 @@ async fn main() -> Result<()> { | |||
| 44 | // Handle the case where no command is provided | 53 | // Handle the case where no command is provided |
| 45 | eprintln!("Error: A command must be provided. Use '--help' for more information."); | 54 | eprintln!("Error: A command must be provided. Use '--help' for more information."); |
| 46 | std::process::exit(1); | 55 | std::process::exit(1); |
| 56 | }; | ||
| 57 | |||
| 58 | if let Err(err) = result { | ||
| 59 | if err.downcast_ref::<CliError>().is_some() { | ||
| 60 | // Already printed styled output to stderr | ||
| 61 | std::process::exit(1); | ||
| 62 | } | ||
| 63 | eprintln!("Error: {err:?}"); | ||
| 64 | std::process::exit(1); | ||
| 47 | } | 65 | } |
| 48 | } | 66 | } |