mirror of
https://codeberg.org/Cyborus/forgejo-cli.git
synced 2024-11-10 12:09:33 +01:00
Merge pull request 'decouple repository info from login info' (#3) from decouple-repo-keys into main
Reviewed-on: https://codeberg.org/Cyborus/forgejo-cli/pulls/3
This commit is contained in:
commit
337c575815
3 changed files with 69 additions and 102 deletions
94
src/keys.rs
94
src/keys.rs
|
@ -42,35 +42,6 @@ impl KeyInfo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current(&self) -> eyre::Result<(HostInfo<'_>, RepoInfo)> {
|
|
||||||
let repo = git2::Repository::open(".")?;
|
|
||||||
let remote_url = get_remote(&repo)?;
|
|
||||||
let login_info = self.get_login(&remote_url)?;
|
|
||||||
|
|
||||||
let mut path = remote_url
|
|
||||||
.path_segments()
|
|
||||||
.ok_or_else(|| eyre!("bad path"))?
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let repo_name = path
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| eyre!("path does not have repo name"))?
|
|
||||||
.to_string();
|
|
||||||
let owner = path
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| eyre!("path does not have owner name"))?
|
|
||||||
.to_string();
|
|
||||||
let base_path = path.join("/");
|
|
||||||
|
|
||||||
let mut url = remote_url;
|
|
||||||
url.set_path(&base_path);
|
|
||||||
let host_info = HostInfo { url, login_info };
|
|
||||||
let repo_info = RepoInfo {
|
|
||||||
owner,
|
|
||||||
name: repo_name,
|
|
||||||
};
|
|
||||||
Ok((host_info, repo_info))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_login(&self, url: &Url) -> eyre::Result<&LoginInfo> {
|
pub fn get_login(&self, url: &Url) -> eyre::Result<&LoginInfo> {
|
||||||
let host_str = url
|
let host_str = url
|
||||||
.host_str()
|
.host_str()
|
||||||
|
@ -87,59 +58,10 @@ impl KeyInfo {
|
||||||
.ok_or_else(|| eyre!("not signed in to {domain}"))?;
|
.ok_or_else(|| eyre!("not signed in to {domain}"))?;
|
||||||
Ok(login_info)
|
Ok(login_info)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HostInfo<'a> {
|
pub fn get_api(&self, url: &Url) -> eyre::Result<forgejo_api::Forgejo> {
|
||||||
url: Url,
|
self.get_login(url)?.api_for(url).map_err(Into::into)
|
||||||
login_info: &'a LoginInfo,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HostInfo<'a> {
|
|
||||||
pub fn api(&self) -> Result<forgejo_api::Forgejo, forgejo_api::ForgejoError> {
|
|
||||||
self.login_info.api_for(self.url())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn url(&self) -> &Url {
|
|
||||||
&self.url
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn username(&self) -> &'a str {
|
|
||||||
&self.login_info.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RepoInfo {
|
|
||||||
owner: String,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RepoInfo {
|
|
||||||
pub fn owner(&self) -> &str {
|
|
||||||
&self.owner
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, Default)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Default)]
|
||||||
|
@ -161,15 +83,3 @@ impl LoginInfo {
|
||||||
forgejo_api::Forgejo::new(&self.key, url.clone())
|
forgejo_api::Forgejo::new(&self.key, url.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_remote(repo: &git2::Repository) -> eyre::Result<Url> {
|
|
||||||
let head = repo.head()?;
|
|
||||||
let branch_name = head.name().ok_or_else(|| eyre!("branch name not UTF-8"))?;
|
|
||||||
let remote_name = repo.branch_upstream_remote(branch_name)?;
|
|
||||||
let remote_name = remote_name
|
|
||||||
.as_str()
|
|
||||||
.ok_or_else(|| eyre!("remote name not UTF-8"))?;
|
|
||||||
let remote = repo.find_remote(remote_name)?;
|
|
||||||
let url = Url::parse(std::str::from_utf8(remote.url_bytes())?)?;
|
|
||||||
Ok(url)
|
|
||||||
}
|
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -39,13 +39,11 @@ async fn main() -> eyre::Result<()> {
|
||||||
Command::Repo(repo_subcommand) => repo_subcommand.run(&keys).await?,
|
Command::Repo(repo_subcommand) => repo_subcommand.run(&keys).await?,
|
||||||
Command::User { host } => {
|
Command::User { host } => {
|
||||||
let host = host.map(|host| Url::parse(&host)).transpose()?;
|
let host = host.map(|host| Url::parse(&host)).transpose()?;
|
||||||
let (url, name) = match host {
|
let url = match host {
|
||||||
Some(url) => (keys.get_login(&url)?.username(), url),
|
Some(url) => url,
|
||||||
None => {
|
None => repo::RepoInfo::get_current()?.url().clone(),
|
||||||
let (host, _) = keys.get_current()?;
|
|
||||||
(host.username(), host.url().clone())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
let name = keys.get_login(&url)?.username();
|
||||||
eprintln!("currently signed in to {name}@{url}");
|
eprintln!("currently signed in to {name}@{url}");
|
||||||
}
|
}
|
||||||
Command::Auth(auth_subcommand) => auth_subcommand.run(&mut keys).await?,
|
Command::Auth(auth_subcommand) => auth_subcommand.run(&mut keys).await?,
|
||||||
|
|
67
src/repo.rs
67
src/repo.rs
|
@ -1,7 +1,66 @@
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
|
use eyre::eyre;
|
||||||
use forgejo_api::CreateRepoOption;
|
use forgejo_api::CreateRepoOption;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
pub struct RepoInfo {
|
||||||
|
owner: String,
|
||||||
|
name: String,
|
||||||
|
url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepoInfo {
|
||||||
|
pub fn get_current() -> eyre::Result<Self> {
|
||||||
|
let repo = git2::Repository::open(".")?;
|
||||||
|
let url = get_remote(&repo)?;
|
||||||
|
|
||||||
|
let mut path = url.path_segments().ok_or_else(|| eyre!("bad path"))?;
|
||||||
|
let owner = path
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| eyre!("path does not have owner name"))?
|
||||||
|
.to_string();
|
||||||
|
let name = path
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| eyre!("path does not have repo name"))?;
|
||||||
|
let name = name.strip_suffix(".git").unwrap_or(name).to_string();
|
||||||
|
|
||||||
|
let repo_info = RepoInfo { owner, name, url };
|
||||||
|
Ok(repo_info)
|
||||||
|
}
|
||||||
|
pub fn owner(&self) -> &str {
|
||||||
|
&self.owner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url(&self) -> &Url {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn host_url(&self) -> Url {
|
||||||
|
let mut url = self.url.clone();
|
||||||
|
url.path_segments_mut()
|
||||||
|
.expect("invalid url: cannot be a base")
|
||||||
|
.pop()
|
||||||
|
.pop();
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_remote(repo: &git2::Repository) -> eyre::Result<Url> {
|
||||||
|
let head = repo.head()?;
|
||||||
|
let branch_name = head.name().ok_or_else(|| eyre!("branch name not UTF-8"))?;
|
||||||
|
let remote_name = repo.branch_upstream_remote(branch_name)?;
|
||||||
|
let remote_name = remote_name
|
||||||
|
.as_str()
|
||||||
|
.ok_or_else(|| eyre!("remote name not UTF-8"))?;
|
||||||
|
let remote = repo.find_remote(remote_name)?;
|
||||||
|
let url = Url::parse(std::str::from_utf8(remote.url_bytes())?)?;
|
||||||
|
Ok(url)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
pub enum RepoCommand {
|
pub enum RepoCommand {
|
||||||
Create {
|
Create {
|
||||||
|
@ -73,8 +132,8 @@ impl RepoCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RepoCommand::Info => {
|
RepoCommand::Info => {
|
||||||
let (host, repo) = keys.get_current()?;
|
let repo = RepoInfo::get_current()?;
|
||||||
let api = host.api()?;
|
let api = keys.get_api(&repo.host_url())?;
|
||||||
let repo = api.get_repo(repo.owner(), repo.name()).await?;
|
let repo = api.get_repo(repo.owner(), repo.name()).await?;
|
||||||
match repo {
|
match repo {
|
||||||
Some(repo) => {
|
Some(repo) => {
|
||||||
|
@ -84,8 +143,8 @@ impl RepoCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RepoCommand::Browse => {
|
RepoCommand::Browse => {
|
||||||
let (host, repo) = keys.get_current()?;
|
let repo = RepoInfo::get_current()?;
|
||||||
let mut url = host.url().clone();
|
let mut url = repo.host_url().clone();
|
||||||
let new_path = format!(
|
let new_path = format!(
|
||||||
"{}/{}/{}",
|
"{}/{}/{}",
|
||||||
url.path().strip_suffix("/").unwrap_or(url.path()),
|
url.path().strip_suffix("/").unwrap_or(url.path()),
|
||||||
|
|
Loading…
Reference in a new issue