summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyborus <cyborus@noreply.localhost>2023-08-18 23:18:41 +0200
committerCyborus <cyborus@noreply.localhost>2023-08-18 23:18:41 +0200
commitf87c12aa8821f8748915c38785240eae1733d443 (patch)
tree63b9d4770cbe87aece0a8162bfff46d0dc661897
parentfix pushing (diff)
parentmove keys info to new file (diff)
downloadforgejo-cli-f87c12aa8821f8748915c38785240eae1733d443.tar.xz
forgejo-cli-f87c12aa8821f8748915c38785240eae1733d443.zip
Merge pull request 'move keys info to new file' (#7) from keys-file into main
-rw-r--r--src/keys.rs156
-rw-r--r--src/main.rs128
2 files changed, 159 insertions, 125 deletions
diff --git a/src/keys.rs b/src/keys.rs
new file mode 100644
index 0000000..047eba1
--- /dev/null
+++ b/src/keys.rs
@@ -0,0 +1,156 @@
+use std::{collections::BTreeMap, io::ErrorKind};
+use eyre::eyre;
+use tokio::io::AsyncWriteExt;
+use url::Url;
+
+#[derive(serde::Serialize, serde::Deserialize, Clone, Default)]
+pub struct KeyInfo {
+ pub hosts: BTreeMap<String, HostInfo>,
+ pub domain_to_name: BTreeMap<String, String>,
+}
+
+impl KeyInfo {
+ fn domain_to_name(&self, domain: &str) -> Option<&str> {
+ self.domain_to_name.get(domain).map(|s| &**s)
+ }
+
+ pub async fn load() -> eyre::Result<Self> {
+ let path = directories::ProjectDirs::from("", "Cyborus", "forgejo-cli")
+ .ok_or_else(|| eyre!("Could not find data directory"))?
+ .data_dir()
+ .join("keys.json");
+ let json = tokio::fs::read(path).await;
+ let this = match json {
+ Ok(x) => serde_json::from_slice::<Self>(&x)?,
+ Err(e) if e.kind() == ErrorKind::NotFound => {
+ eprintln!("keys file not found, creating");
+ Self::default()
+ }
+ Err(e) => return Err(e.into()),
+ };
+ Ok(this)
+ }
+
+ pub async fn save(&self) -> eyre::Result<()> {
+ let json = serde_json::to_vec_pretty(self)?;
+ let dirs = directories::ProjectDirs::from("", "Cyborus", "forgejo-cli")
+ .ok_or_else(|| eyre!("Could not find data directory"))?;
+ let path = dirs.data_dir();
+
+ tokio::fs::create_dir_all(path).await?;
+
+ tokio::fs::File::create(path.join("keys.json"))
+ .await?
+ .write_all(&json)
+ .await?;
+
+ Ok(())
+ }
+
+ pub async fn get_current_host_and_repo(&self) -> eyre::Result<(&str, &HostInfo, String)> {
+ let remotes = get_remotes().await?;
+ let remote = get_remote(&remotes).await?;
+ let host_str = remote
+ .host_str()
+ .ok_or_else(|| eyre!("remote url does not have host"))?;
+ let domain = if let Some(port) = remote.port() {
+ format!("{}:{}", host_str, port)
+ } else {
+ host_str.to_owned()
+ };
+ let name = self
+ .domain_to_name(&domain)
+ .ok_or_else(|| eyre!("unknown remote"))?;
+
+ let (name, host) = self
+ .hosts
+ .get_key_value(name)
+ .ok_or_else(|| eyre!("not signed in to {domain}"))?;
+ Ok((name, host, repo_from_url(&remote)?.into()))
+ }
+
+ pub async fn get_current_host(&self) -> eyre::Result<(&str, &HostInfo)> {
+ let (name, host, _) = self.get_current_host_and_repo().await?;
+ Ok((name, host))
+ }
+
+ async fn get_current_user(&self) -> eyre::Result<(&str, &UserInfo)> {
+ let user = self.get_current_host().await?.1.get_current_user()?;
+
+ Ok(user)
+ }
+}
+
+fn repo_from_url(url: &Url) -> eyre::Result<&str> {
+ let mut iter = url
+ .path_segments()
+ .ok_or_else(|| eyre!("failed to get path from url"))?;
+ soft_assert::soft_assert!(
+ matches!(iter.next(), Some(_)),
+ Err(eyre!("path should have 2 segments, has none"))
+ );
+ let repo = iter
+ .next()
+ .ok_or_else(|| eyre!("path should have 2 segments, has only 1"))?;
+ let repo = repo.strip_suffix(".git").unwrap_or(repo);
+ soft_assert::soft_assert!(
+ matches!(iter.next(), None),
+ Err(eyre!("path should have 2 segments, has more"))
+ );
+ Ok(repo)
+}
+
+#[derive(serde::Serialize, serde::Deserialize, Clone)]
+pub struct HostInfo {
+ pub default: Option<String>,
+ pub url: Url,
+ pub users: BTreeMap<String, UserInfo>,
+}
+
+impl HostInfo {
+ pub fn get_current_user(&self) -> eyre::Result<(&str, &UserInfo)> {
+ if self.users.len() == 1 {
+ let (s, k) = self.users.first_key_value().unwrap();
+ return Ok((s, k));
+ }
+ if let Some(default) = self.default.as_ref() {
+ if let Some(default_info) = self.users.get(default) {
+ return Ok((default, default_info));
+ }
+ }
+
+ Err(eyre!("could not find user"))
+ }
+}
+
+#[derive(serde::Serialize, serde::Deserialize, Clone, Default)]
+pub struct UserInfo {
+ pub name: String,
+ pub key: String,
+}
+
+async fn get_remotes() -> eyre::Result<Vec<(String, Url)>> {
+ let repo = git2::Repository::open(".")?;
+ let remotes = repo
+ .remotes()?
+ .iter()
+ .filter_map(|name| {
+ let name = name?.to_string();
+ let url = Url::parse(repo.find_remote(&name).ok()?.url()?).ok()?;
+ Some((name, url))
+ })
+ .collect::<Vec<_>>();
+ Ok(remotes)
+}
+
+async fn get_remote(remotes: &[(String, Url)]) -> eyre::Result<Url> {
+ let url = if remotes.len() == 1 {
+ remotes[0].1.clone()
+ } else if let Some((_, url)) = remotes.iter().find(|(name, _)| *name == "origin") {
+ url.clone()
+ } else {
+ eyre::bail!("could not find remote");
+ };
+ Ok(url)
+}
+
diff --git a/src/main.rs b/src/main.rs
index 3ab1338..f43252a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,6 +6,9 @@ use forgejo_api::{CreateRepoOption, Forgejo};
use tokio::io::AsyncWriteExt;
use url::Url;
+mod keys;
+use keys::*;
+
#[derive(Parser, Debug)]
pub struct App {
#[clap(subcommand)]
@@ -278,128 +281,3 @@ async fn get_remote(remotes: &[(String, Url)]) -> eyre::Result<Url> {
Ok(url)
}
-#[derive(serde::Serialize, serde::Deserialize, Clone, Default)]
-struct KeyInfo {
- hosts: BTreeMap<String, HostInfo>,
- domain_to_name: BTreeMap<String, String>,
-}
-
-impl KeyInfo {
- fn domain_to_name(&self, domain: &str) -> Option<&str> {
- self.domain_to_name.get(domain).map(|s| &**s)
- }
-
- async fn load() -> eyre::Result<Self> {
- let path = directories::ProjectDirs::from("", "Cyborus", "forgejo-cli")
- .ok_or_else(|| eyre!("Could not find data directory"))?
- .data_dir()
- .join("keys.json");
- let json = tokio::fs::read(path).await;
- let this = match json {
- Ok(x) => serde_json::from_slice::<Self>(&x)?,
- Err(e) if e.kind() == ErrorKind::NotFound => {
- eprintln!("keys file not found, creating");
- Self::default()
- }
- Err(e) => return Err(e.into()),
- };
- Ok(this)
- }
-
- async fn save(&self) -> eyre::Result<()> {
- let json = serde_json::to_vec_pretty(self)?;
- let dirs = directories::ProjectDirs::from("", "Cyborus", "forgejo-cli")
- .ok_or_else(|| eyre!("Could not find data directory"))?;
- let path = dirs.data_dir();
-
- tokio::fs::create_dir_all(path).await?;
-
- tokio::fs::File::create(path.join("keys.json"))
- .await?
- .write_all(&json)
- .await?;
-
- Ok(())
- }
-
- async fn get_current_host_and_repo(&self) -> eyre::Result<(&str, &HostInfo, String)> {
- let remotes = get_remotes().await?;
- let remote = get_remote(&remotes).await?;
- let host_str = remote
- .host_str()
- .ok_or_else(|| eyre!("remote url does not have host"))?;
- let domain = if let Some(port) = remote.port() {
- format!("{}:{}", host_str, port)
- } else {
- host_str.to_owned()
- };
- let name = self
- .domain_to_name(&domain)
- .ok_or_else(|| eyre!("unknown remote"))?;
-
- let (name, host) = self
- .hosts
- .get_key_value(name)
- .ok_or_else(|| eyre!("not signed in to {domain}"))?;
- Ok((name, host, repo_from_url(&remote)?.into()))
- }
-
- async fn get_current_host(&self) -> eyre::Result<(&str, &HostInfo)> {
- let (name, host, _) = self.get_current_host_and_repo().await?;
- Ok((name, host))
- }
-
- async fn get_current_user(&self) -> eyre::Result<(&str, &UserInfo)> {
- let user = self.get_current_host().await?.1.get_current_user()?;
-
- Ok(user)
- }
-}
-
-fn repo_from_url(url: &Url) -> eyre::Result<&str> {
- let mut iter = url
- .path_segments()
- .ok_or_else(|| eyre!("failed to get path from url"))?;
- soft_assert::soft_assert!(
- matches!(iter.next(), Some(_)),
- Err(eyre!("path should have 2 segments, has none"))
- );
- let repo = iter
- .next()
- .ok_or_else(|| eyre!("path should have 2 segments, has only 1"))?;
- let repo = repo.strip_suffix(".git").unwrap_or(repo);
- soft_assert::soft_assert!(
- matches!(iter.next(), None),
- Err(eyre!("path should have 2 segments, has more"))
- );
- Ok(repo)
-}
-
-#[derive(serde::Serialize, serde::Deserialize, Clone)]
-struct HostInfo {
- default: Option<String>,
- url: Url,
- users: BTreeMap<String, UserInfo>,
-}
-
-impl HostInfo {
- fn get_current_user(&self) -> eyre::Result<(&str, &UserInfo)> {
- if self.users.len() == 1 {
- let (s, k) = self.users.first_key_value().unwrap();
- return Ok((s, k));
- }
- if let Some(default) = self.default.as_ref() {
- if let Some(default_info) = self.users.get(default) {
- return Ok((default, default_info));
- }
- }
-
- Err(eyre!("could not find user"))
- }
-}
-
-#[derive(serde::Serialize, serde::Deserialize, Clone, Default)]
-struct UserInfo {
- name: String,
- key: String,
-}