upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/bin/ngit/sub_commands
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-03-05 15:03:37 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-03-05 15:06:02 +0000
commit09c3ae91830bd9c7543b401b19f8c65a15205d32 (patch)
tree3c7505301c9868cd421fbf0097ed946b9f4b9088 /src/bin/ngit/sub_commands
parent37244449d6d0d58bb639f181bd15092de1acaaee (diff)
fix(whoami): detect and fall back to system git config for nostr login
Add GitSystem to SignerInfoSource so credentials stored in the system git config (/etc/gitconfig) are included in the priority fallback chain (local > global > system) and shown as a separate level in whoami output.
Diffstat (limited to 'src/bin/ngit/sub_commands')
-rw-r--r--src/bin/ngit/sub_commands/whoami.rs77
1 files changed, 50 insertions, 27 deletions
diff --git a/src/bin/ngit/sub_commands/whoami.rs b/src/bin/ngit/sub_commands/whoami.rs
index 19ce573..5c0a461 100644
--- a/src/bin/ngit/sub_commands/whoami.rs
+++ b/src/bin/ngit/sub_commands/whoami.rs
@@ -41,8 +41,10 @@ struct WhoamiJson {
41 local: Option<UserJson>, 41 local: Option<UserJson>,
42 #[serde(skip_serializing_if = "Option::is_none")] 42 #[serde(skip_serializing_if = "Option::is_none")]
43 global: Option<UserJson>, 43 global: Option<UserJson>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 system: Option<UserJson>,
44 /// The account that would be used for operations in the current context 46 /// The account that would be used for operations in the current context
45 /// (local takes priority over global). 47 /// (local > global > system, matching git's priority order).
46 #[serde(skip_serializing_if = "Option::is_none")] 48 #[serde(skip_serializing_if = "Option::is_none")]
47 active: Option<UserJson>, 49 active: Option<UserJson>,
48} 50}
@@ -62,7 +64,7 @@ pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> {
62 64
63 let signer_info = extract_signer_cli_arguments(args).unwrap_or(None); 65 let signer_info = extract_signer_cli_arguments(args).unwrap_or(None);
64 66
65 // Try to load local login (silent, no prompts) 67 // Try to load login from each config level (silent, no prompts)
66 let local = load_user_for_scope( 68 let local = load_user_for_scope(
67 git_repo.as_ref(), 69 git_repo.as_ref(),
68 signer_info.as_ref(), 70 signer_info.as_ref(),
@@ -71,7 +73,6 @@ pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> {
71 ) 73 )
72 .await; 74 .await;
73 75
74 // Try to load global login (silent, no prompts)
75 let global = load_user_for_scope( 76 let global = load_user_for_scope(
76 git_repo.as_ref(), 77 git_repo.as_ref(),
77 signer_info.as_ref(), 78 signer_info.as_ref(),
@@ -80,45 +81,67 @@ pub async fn launch(args: &Cli, command_args: &SubCommandArgs) -> Result<()> {
80 ) 81 )
81 .await; 82 .await;
82 83
84 let system = load_user_for_scope(
85 git_repo.as_ref(),
86 signer_info.as_ref(),
87 client.as_ref(),
88 SignerInfoSource::GitSystem,
89 )
90 .await;
91
83 if let Some(client) = client { 92 if let Some(client) = client {
84 client.disconnect().await?; 93 client.disconnect().await?;
85 } 94 }
86 95
96 // Active account follows git's priority order: local > global > system
97 let active_scope = if local.is_some() {
98 Some("local")
99 } else if global.is_some() {
100 Some("global")
101 } else if system.is_some() {
102 Some("system")
103 } else {
104 None
105 };
106
87 if command_args.json { 107 if command_args.json {
88 // active = local if present, else global 108 let active = active_scope.and_then(|scope| match scope {
89 let active = local 109 "local" => local.as_ref().map(|u| make_user_json(u, scope)),
90 .as_ref() 110 "global" => global.as_ref().map(|u| make_user_json(u, scope)),
91 .map(|u| make_user_json(u, "local")) 111 "system" => system.as_ref().map(|u| make_user_json(u, scope)),
92 .or_else(|| global.as_ref().map(|u| make_user_json(u, "global"))); 112 _ => None,
113 });
93 114
94 let output = WhoamiJson { 115 let output = WhoamiJson {
95 local: local.as_ref().map(|u| make_user_json(u, "local")), 116 local: local.as_ref().map(|u| make_user_json(u, "local")),
96 global: global.as_ref().map(|u| make_user_json(u, "global")), 117 global: global.as_ref().map(|u| make_user_json(u, "global")),
118 system: system.as_ref().map(|u| make_user_json(u, "system")),
97 active, 119 active,
98 }; 120 };
99 println!("{}", serde_json::to_string_pretty(&output)?); 121 println!("{}", serde_json::to_string_pretty(&output)?);
122 } else if local.is_none() && global.is_none() && system.is_none() {
123 println!("not logged in");
124 println!();
125 println!("use `ngit account login` to log in");
100 } else { 126 } else {
101 match (local.as_ref(), global.as_ref()) { 127 type UserEntry = Option<(String, String, Option<String>)>;
102 (None, None) => { 128 let entries: &[(&str, &UserEntry)] =
103 println!("not logged in"); 129 &[("local", &local), ("global", &global), ("system", &system)];
104 println!(); 130 let mut first = true;
105 println!("use `ngit account login` to log in"); 131 for (scope, user) in entries {
106 } 132 if let Some(u) = user {
107 (Some(u), None) => { 133 if !first {
108 println!("logged in to local repository as:"); 134 println!();
135 }
136 first = false;
137 let is_active = active_scope == Some(scope);
138 if is_active {
139 println!("{scope} (active):");
140 } else {
141 println!("{scope}:");
142 }
109 print_user_human(u); 143 print_user_human(u);
110 } 144 }
111 (None, Some(u)) => {
112 println!("logged in globally as:");
113 print_user_human(u);
114 }
115 (Some(local_u), Some(global_u)) => {
116 println!("local (active):");
117 print_user_human(local_u);
118 println!();
119 println!("global:");
120 print_user_human(global_u);
121 }
122 } 145 }
123 } 146 }
124 147