From 318e467b158b158cf9eb843318dc14141d1b8c54 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Sun, 21 May 2023 11:27:04 +0000 Subject: main and remaining subcommands --- src/main.rs | 115 ++++++++++++++++++++++++++++++++++++++++ src/sub_commands/change_user.rs | 63 ++++++++++++++++++++++ src/sub_commands/fetch.rs | 22 ++++++++ src/sub_commands/mod.rs | 9 ++++ src/sub_commands/pull.rs | 26 +++++++++ src/sub_commands/push.rs | 31 +++++++++++ src/sub_commands/rebroadcast.rs | 68 ++++++++++++++++++++++++ 7 files changed, 334 insertions(+) create mode 100644 src/main.rs create mode 100644 src/sub_commands/change_user.rs create mode 100644 src/sub_commands/fetch.rs create mode 100644 src/sub_commands/mod.rs create mode 100644 src/sub_commands/pull.rs create mode 100644 src/sub_commands/push.rs create mode 100644 src/sub_commands/rebroadcast.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e819b5a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,115 @@ +use clap::{Parser, Subcommand}; +use nostr_sdk::Result; + +mod branch_refs; +mod sub_commands; +mod funcs; +mod fetch_pull_push; +mod groups; +mod merge; +mod pull_request; +mod repos; +mod patch; +mod ngit_tag; +mod kind; +mod utils; +mod config; +mod repo_config; +mod cli_helpers; + +/// Simple CLI application to use git through nostr +#[derive(Parser)] +#[command(name = "ngit")] +#[command(author = "DanConwayDev , +} + +#[derive(Subcommand)] +enum Commands { + /// Initialize a repoistory + Clone(sub_commands::clone::CloneSubCommand), + /// Initialize a repoistory + Init(sub_commands::init::InitSubCommand), + /// Pull to events and relays + Pull(sub_commands::pull::PullSubCommand), + /// Push to events and relays + Push(sub_commands::push::PushSubCommand), + /// Merge to events and relays + Merge(sub_commands::merge::MergeSubCommand), + /// Fetch from relays + Fetch(sub_commands::fetch::FetchSubCommand), + /// View active PRs from relays + Prs(sub_commands::prs::PrsSubCommand), + /// rebroadcast all repository events + Rebroadcast(sub_commands::rebroadcast::RebroadcastSubCommand), + ChangeUser(sub_commands::change_user::ChangeUserSubCommand), +} + +fn main() -> Result<()> { + println!("ngit prototype v0.0.1-alpha"); + // Parse input + let args: Cli = Cli::parse(); + + // Post event + match &args.command { + Commands::Init(sub_command_args) => sub_commands::init::create_and_broadcast_init( + args.relays, + sub_command_args, + ), + Commands::Clone(sub_command_args) => { + sub_commands::clone::clone_from_relays( + args.relays, + sub_command_args, + ); + Ok(()) + }, + Commands::Pull(sub_command_args) => { + sub_commands::pull::pull_from_relays( + None, + sub_command_args, + ); + Ok(()) + }, + Commands::Push(sub_command_args) => { + sub_commands::push::push( + sub_command_args, + ); + Ok(()) + } + Commands::Merge(sub_command_args) => { + sub_commands::merge::merge( + sub_command_args, + ); + Ok(()) + } + Commands::Fetch(_sub_command_args) => { + sub_commands::fetch::fetch_from_relays(None); + Ok(()) + }, + Commands::Prs(sub_command_args) => { + sub_commands::prs::prs( + sub_command_args, + ); + Ok(()) + } + Commands::Rebroadcast(sub_command_args) => { + sub_commands::rebroadcast::rebroadcast( + sub_command_args, + ); + Ok(()) + } + Commands::ChangeUser(sub_command_args) => { + sub_commands::change_user::change_user( + sub_command_args, + ); + Ok(()) + } + } +} diff --git a/src/sub_commands/change_user.rs b/src/sub_commands/change_user.rs new file mode 100644 index 0000000..ac15d1d --- /dev/null +++ b/src/sub_commands/change_user.rs @@ -0,0 +1,63 @@ + + +use clap::Args; +use dialoguer::{Select, theme::ColorfulTheme, Confirm, Password}; +use nostr::{Keys, prelude::{FromSkStr}}; + +use crate::{config::{load_config, save_conifg}}; + +#[derive(Args)] +pub struct ChangeUserSubCommand { +} + +pub fn change_user(_sub_command_args: &ChangeUserSubCommand) { + + let mut cfg = load_config(); + + if cfg.private_key.is_some() { + if !Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("overwrite existing?") + .default(false) + .interact() + .unwrap() { + return; + } + } + + let selection = Select::with_theme(&ColorfulTheme::default()) + .items(&vec!["enter existing private key", "generate new keys"]) + .default(0) + .with_prompt("no keys are stored") + .interact().unwrap(); + + let key = match selection { + 0 => { + let mut prompt = "secret key (nsec, hex, etc)"; + loop { + let pk: String = Password::with_theme(&ColorfulTheme::default()) + .with_prompt(prompt) + .interact() + .unwrap(); + match Keys::from_sk_str(&pk) { + Ok(key) => { break key; }, + Err(_e) => { prompt = "error interpeting secret key. try again with nsec, hex, etc"; }, + } + } + } + _ => Keys::generate(), + }; + cfg.private_key = Some(key.secret_key().unwrap()); + + if cfg.default_admin_group_event_serialized.is_some() { + if !Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("remove default admin group? If not permissions on new repositories can only be changed by the previous user.") + .default(true) + .interact() + .unwrap() { + cfg.default_admin_group_event_serialized = None; + } + } + + save_conifg(&cfg); + println!("private key updated") +} diff --git a/src/sub_commands/fetch.rs b/src/sub_commands/fetch.rs new file mode 100644 index 0000000..36f1954 --- /dev/null +++ b/src/sub_commands/fetch.rs @@ -0,0 +1,22 @@ +use clap::Args; +use nostr::Keys; + +use crate::fetch_pull_push::fetch_pull_push; + +#[derive(Args)] +pub struct FetchSubCommand { +} + +pub fn fetch_from_relays(keys: Option<&Keys>) { + + fetch_pull_push( + keys, + false, + false, + None, + false, + None, + None, + ); + +} diff --git a/src/sub_commands/mod.rs b/src/sub_commands/mod.rs new file mode 100644 index 0000000..280f959 --- /dev/null +++ b/src/sub_commands/mod.rs @@ -0,0 +1,9 @@ +pub mod clone; +pub mod init; +pub mod pull; +pub mod push; +pub mod prs; +pub mod fetch; +pub mod merge; +pub mod rebroadcast; +pub mod change_user; diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs new file mode 100644 index 0000000..0030dbe --- /dev/null +++ b/src/sub_commands/pull.rs @@ -0,0 +1,26 @@ + + +use clap::Args; +use nostr::{Keys}; + +use crate::{fetch_pull_push::fetch_pull_push}; + +#[derive(Args)] +pub struct PullSubCommand { + /// branch nevent or hex to pull into a new local branch + #[arg(short, long)] + pub branch: Option, +} + +pub fn pull_from_relays(keys: Option<&Keys>, sub_command_args: &PullSubCommand) { + + fetch_pull_push( + keys, + true, + false, + sub_command_args.branch.clone(), + false, + None, + None, + ); +} diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs new file mode 100644 index 0000000..e0fda7b --- /dev/null +++ b/src/sub_commands/push.rs @@ -0,0 +1,31 @@ + +use clap::{Args}; + +use crate::fetch_pull_push::fetch_pull_push; + +#[derive(Args)] +struct PushRepo { + /// Relays + #[arg(short, long)] + relays: Option, +} + +#[derive(Args)] +pub struct PushSubCommand { +} + +pub fn push( + _sub_command_args: &PushSubCommand, +) { + + fetch_pull_push( + None, + false, + true, + None, + false, + None, + None, + ); + +} diff --git a/src/sub_commands/rebroadcast.rs b/src/sub_commands/rebroadcast.rs new file mode 100644 index 0000000..d3ece23 --- /dev/null +++ b/src/sub_commands/rebroadcast.rs @@ -0,0 +1,68 @@ + + +use std::fs; + +use clap::Args; + +use nostr::{Keys}; + +use crate::{cli_helpers::select_relays, config::load_config, utils::{create_client, load_event}}; + +#[derive(Args)] +pub struct RebroadcastSubCommand { +} + +pub fn rebroadcast( + _sub_command_args: &RebroadcastSubCommand, +) { + + // get relay input + let relays = select_relays( + &mut load_config(), + &vec![], + ) + .expect("relays to be selected"); + + let client = create_client(&Keys::generate(), relays) + .expect("create_client to return client for create_and_broadcast_patches"); + + let repo_dir_path = std::env::current_dir().unwrap(); + + // cycle through directories and send events + for dir_name in [ + "groups", + "branches", + "patches", + "merges", + "prs", + "issues", + "comments", + ] { + if !repo_dir_path.join(".ngit").exists() { + println!("this isn't a repository here to rebroadcast") + } + let dir_path = repo_dir_path.join(".ngit").join(&dir_name); + if dir_path.exists() { + let dir = fs::read_dir(&dir_path) + .expect("read_dir to produce ReadDir from a path that exists"); + // get json in directories + for entry in dir { + let path = entry + .expect("DirEntry to return from ReadDir") + .path(); + // send event + match client.send_event( + load_event(&path) + .expect("every file in .ngit paths is a valid json event") + ) { + Ok(_) => { + println!("sent: {}", &path.to_string_lossy()); + }, + // TODO: this isn't working - if a relay is specified with a type it will wait 30ish secs and then return successful + Err(e) => { println!("error broadcasting event: {}",e); }, + } + // TODO: better error handling here / reporting. potentially warn if taking a while and report on troublesome relays + } + } + } +} -- cgit v1.2.3