upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs115
-rw-r--r--src/sub_commands/change_user.rs63
-rw-r--r--src/sub_commands/fetch.rs22
-rw-r--r--src/sub_commands/mod.rs9
-rw-r--r--src/sub_commands/pull.rs26
-rw-r--r--src/sub_commands/push.rs31
-rw-r--r--src/sub_commands/rebroadcast.rs68
7 files changed, 334 insertions, 0 deletions
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 @@
1use clap::{Parser, Subcommand};
2use nostr_sdk::Result;
3
4mod branch_refs;
5mod sub_commands;
6mod funcs;
7mod fetch_pull_push;
8mod groups;
9mod merge;
10mod pull_request;
11mod repos;
12mod patch;
13mod ngit_tag;
14mod kind;
15mod utils;
16mod config;
17mod repo_config;
18mod cli_helpers;
19
20/// Simple CLI application to use git through nostr
21#[derive(Parser)]
22#[command(name = "ngit")]
23#[command(author = "DanConwayDev <DanConwayDev@protonmail.com")]
24#[command(version = "0.0.1")]
25#[command(author, version, about, long_about = None)]
26struct Cli {
27 #[command(subcommand)]
28 command: Commands,
29 /// Relay to connect to
30 #[arg(short, long, action = clap::ArgAction::Append)]
31 relays: Vec<String>,
32}
33
34#[derive(Subcommand)]
35enum Commands {
36 /// Initialize a repoistory
37 Clone(sub_commands::clone::CloneSubCommand),
38 /// Initialize a repoistory
39 Init(sub_commands::init::InitSubCommand),
40 /// Pull to events and relays
41 Pull(sub_commands::pull::PullSubCommand),
42 /// Push to events and relays
43 Push(sub_commands::push::PushSubCommand),
44 /// Merge to events and relays
45 Merge(sub_commands::merge::MergeSubCommand),
46 /// Fetch from relays
47 Fetch(sub_commands::fetch::FetchSubCommand),
48 /// View active PRs from relays
49 Prs(sub_commands::prs::PrsSubCommand),
50 /// rebroadcast all repository events
51 Rebroadcast(sub_commands::rebroadcast::RebroadcastSubCommand),
52 ChangeUser(sub_commands::change_user::ChangeUserSubCommand),
53}
54
55fn main() -> Result<()> {
56 println!("ngit prototype v0.0.1-alpha");
57 // Parse input
58 let args: Cli = Cli::parse();
59
60 // Post event
61 match &args.command {
62 Commands::Init(sub_command_args) => sub_commands::init::create_and_broadcast_init(
63 args.relays,
64 sub_command_args,
65 ),
66 Commands::Clone(sub_command_args) => {
67 sub_commands::clone::clone_from_relays(
68 args.relays,
69 sub_command_args,
70 );
71 Ok(())
72 },
73 Commands::Pull(sub_command_args) => {
74 sub_commands::pull::pull_from_relays(
75 None,
76 sub_command_args,
77 );
78 Ok(())
79 },
80 Commands::Push(sub_command_args) => {
81 sub_commands::push::push(
82 sub_command_args,
83 );
84 Ok(())
85 }
86 Commands::Merge(sub_command_args) => {
87 sub_commands::merge::merge(
88 sub_command_args,
89 );
90 Ok(())
91 }
92 Commands::Fetch(_sub_command_args) => {
93 sub_commands::fetch::fetch_from_relays(None);
94 Ok(())
95 },
96 Commands::Prs(sub_command_args) => {
97 sub_commands::prs::prs(
98 sub_command_args,
99 );
100 Ok(())
101 }
102 Commands::Rebroadcast(sub_command_args) => {
103 sub_commands::rebroadcast::rebroadcast(
104 sub_command_args,
105 );
106 Ok(())
107 }
108 Commands::ChangeUser(sub_command_args) => {
109 sub_commands::change_user::change_user(
110 sub_command_args,
111 );
112 Ok(())
113 }
114 }
115}
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 @@
1
2
3use clap::Args;
4use dialoguer::{Select, theme::ColorfulTheme, Confirm, Password};
5use nostr::{Keys, prelude::{FromSkStr}};
6
7use crate::{config::{load_config, save_conifg}};
8
9#[derive(Args)]
10pub struct ChangeUserSubCommand {
11}
12
13pub fn change_user(_sub_command_args: &ChangeUserSubCommand) {
14
15 let mut cfg = load_config();
16
17 if cfg.private_key.is_some() {
18 if !Confirm::with_theme(&ColorfulTheme::default())
19 .with_prompt("overwrite existing?")
20 .default(false)
21 .interact()
22 .unwrap() {
23 return;
24 }
25 }
26
27 let selection = Select::with_theme(&ColorfulTheme::default())
28 .items(&vec!["enter existing private key", "generate new keys"])
29 .default(0)
30 .with_prompt("no keys are stored")
31 .interact().unwrap();
32
33 let key = match selection {
34 0 => {
35 let mut prompt = "secret key (nsec, hex, etc)";
36 loop {
37 let pk: String = Password::with_theme(&ColorfulTheme::default())
38 .with_prompt(prompt)
39 .interact()
40 .unwrap();
41 match Keys::from_sk_str(&pk) {
42 Ok(key) => { break key; },
43 Err(_e) => { prompt = "error interpeting secret key. try again with nsec, hex, etc"; },
44 }
45 }
46 }
47 _ => Keys::generate(),
48 };
49 cfg.private_key = Some(key.secret_key().unwrap());
50
51 if cfg.default_admin_group_event_serialized.is_some() {
52 if !Confirm::with_theme(&ColorfulTheme::default())
53 .with_prompt("remove default admin group? If not permissions on new repositories can only be changed by the previous user.")
54 .default(true)
55 .interact()
56 .unwrap() {
57 cfg.default_admin_group_event_serialized = None;
58 }
59 }
60
61 save_conifg(&cfg);
62 println!("private key updated")
63}
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 @@
1use clap::Args;
2use nostr::Keys;
3
4use crate::fetch_pull_push::fetch_pull_push;
5
6#[derive(Args)]
7pub struct FetchSubCommand {
8}
9
10pub fn fetch_from_relays(keys: Option<&Keys>) {
11
12 fetch_pull_push(
13 keys,
14 false,
15 false,
16 None,
17 false,
18 None,
19 None,
20 );
21
22}
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 @@
1pub mod clone;
2pub mod init;
3pub mod pull;
4pub mod push;
5pub mod prs;
6pub mod fetch;
7pub mod merge;
8pub mod rebroadcast;
9pub 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 @@
1
2
3use clap::Args;
4use nostr::{Keys};
5
6use crate::{fetch_pull_push::fetch_pull_push};
7
8#[derive(Args)]
9pub struct PullSubCommand {
10 /// branch nevent or hex to pull into a new local branch
11 #[arg(short, long)]
12 pub branch: Option<String>,
13}
14
15pub fn pull_from_relays(keys: Option<&Keys>, sub_command_args: &PullSubCommand) {
16
17 fetch_pull_push(
18 keys,
19 true,
20 false,
21 sub_command_args.branch.clone(),
22 false,
23 None,
24 None,
25 );
26}
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 @@
1
2use clap::{Args};
3
4use crate::fetch_pull_push::fetch_pull_push;
5
6#[derive(Args)]
7struct PushRepo {
8 /// Relays
9 #[arg(short, long)]
10 relays: Option<String>,
11}
12
13#[derive(Args)]
14pub struct PushSubCommand {
15}
16
17pub fn push(
18 _sub_command_args: &PushSubCommand,
19) {
20
21 fetch_pull_push(
22 None,
23 false,
24 true,
25 None,
26 false,
27 None,
28 None,
29 );
30
31}
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 @@
1
2
3use std::fs;
4
5use clap::Args;
6
7use nostr::{Keys};
8
9use crate::{cli_helpers::select_relays, config::load_config, utils::{create_client, load_event}};
10
11#[derive(Args)]
12pub struct RebroadcastSubCommand {
13}
14
15pub fn rebroadcast(
16 _sub_command_args: &RebroadcastSubCommand,
17) {
18
19 // get relay input
20 let relays = select_relays(
21 &mut load_config(),
22 &vec![],
23 )
24 .expect("relays to be selected");
25
26 let client = create_client(&Keys::generate(), relays)
27 .expect("create_client to return client for create_and_broadcast_patches");
28
29 let repo_dir_path = std::env::current_dir().unwrap();
30
31 // cycle through directories and send events
32 for dir_name in [
33 "groups",
34 "branches",
35 "patches",
36 "merges",
37 "prs",
38 "issues",
39 "comments",
40 ] {
41 if !repo_dir_path.join(".ngit").exists() {
42 println!("this isn't a repository here to rebroadcast")
43 }
44 let dir_path = repo_dir_path.join(".ngit").join(&dir_name);
45 if dir_path.exists() {
46 let dir = fs::read_dir(&dir_path)
47 .expect("read_dir to produce ReadDir from a path that exists");
48 // get json in directories
49 for entry in dir {
50 let path = entry
51 .expect("DirEntry to return from ReadDir")
52 .path();
53 // send event
54 match client.send_event(
55 load_event(&path)
56 .expect("every file in .ngit paths is a valid json event")
57 ) {
58 Ok(_) => {
59 println!("sent: {}", &path.to_string_lossy());
60 },
61 // TODO: this isn't working - if a relay is specified with a type it will wait 30ish secs and then return successful
62 Err(e) => { println!("error broadcasting event: {}",e); },
63 }
64 // TODO: better error handling here / reporting. potentially warn if taking a while and report on troublesome relays
65 }
66 }
67 }
68}