rad: preparation for the rad remote commands
This commits introduces just a couple of helper functions in order to work with the `rad remote *` commands. Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
442e8a7128
commit
0468a1a757
|
|
@ -10,12 +10,14 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use radicle::crypto::ssh;
|
use radicle::crypto::ssh;
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
use radicle::git::raw as git2;
|
use radicle::git::raw as git2;
|
||||||
use radicle::git::{Version, VERSION_REQUIRED};
|
use radicle::git::{Version, VERSION_REQUIRED};
|
||||||
use radicle::prelude::{Id, NodeId};
|
use radicle::prelude::{Id, NodeId};
|
||||||
|
use radicle::storage::git::transport;
|
||||||
|
|
||||||
pub use radicle::git::raw::{
|
pub use radicle::git::raw::{
|
||||||
build::CheckoutBuilder, AnnotatedCommit, Commit, Direction, ErrorCode, MergeAnalysis,
|
build::CheckoutBuilder, AnnotatedCommit, Commit, Direction, ErrorCode, MergeAnalysis,
|
||||||
|
|
@ -60,6 +62,45 @@ impl From<String> for Rev {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum RemoteError {
|
||||||
|
#[error("url malformed: {0}")]
|
||||||
|
ParseUrl(#[from] transport::local::UrlError),
|
||||||
|
#[error("remote `url` not found")]
|
||||||
|
MissingUrl,
|
||||||
|
#[error("remote `name` not found")]
|
||||||
|
MissingName,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Remote<'a> {
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) url: radicle::git::Url,
|
||||||
|
inner: git2::Remote<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Remote<'_> {
|
||||||
|
pub fn refspecs(&self) -> git2::Refspecs {
|
||||||
|
self.inner.refspecs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<git2::Remote<'a>> for Remote<'a> {
|
||||||
|
type Error = RemoteError;
|
||||||
|
|
||||||
|
fn try_from(value: git2::Remote<'a>) -> Result<Self, Self::Error> {
|
||||||
|
let url = value.url().map_or(Err(RemoteError::MissingUrl), |url| {
|
||||||
|
Ok(radicle::git::Url::from_str(url)?)
|
||||||
|
})?;
|
||||||
|
let name = value.name().ok_or(RemoteError::MissingName)?;
|
||||||
|
Ok(Self {
|
||||||
|
name: name.to_owned(),
|
||||||
|
url,
|
||||||
|
inner: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the git repository in the current directory.
|
/// Get the git repository in the current directory.
|
||||||
pub fn repository() -> Result<Repository, anyhow::Error> {
|
pub fn repository() -> Result<Repository, anyhow::Error> {
|
||||||
match Repository::open(".") {
|
match Repository::open(".") {
|
||||||
|
|
@ -175,24 +216,27 @@ pub fn is_signing_configured(repo: &Path) -> Result<bool, anyhow::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the list of radicle remotes for the given repository.
|
/// Return the list of radicle remotes for the given repository.
|
||||||
pub fn remotes(repo: &git2::Repository) -> anyhow::Result<Vec<(String, NodeId)>> {
|
pub fn rad_remotes(repo: &git2::Repository) -> anyhow::Result<Vec<Remote>> {
|
||||||
let mut remotes = Vec::new();
|
let remotes: Vec<_> = repo
|
||||||
|
.remotes()?
|
||||||
for name in repo.remotes().iter().flatten().flatten() {
|
.iter()
|
||||||
let remote = repo.find_remote(name)?;
|
.filter_map(|name| {
|
||||||
for refspec in remote.refspecs() {
|
let remote = repo.find_remote(name?).ok()?;
|
||||||
if refspec.direction() != git2::Direction::Fetch {
|
Remote::try_from(remote).ok()
|
||||||
continue;
|
})
|
||||||
}
|
.collect();
|
||||||
if let Some((peer, _)) = refspec.src().and_then(self::parse_remote) {
|
|
||||||
remotes.push((name.to_owned(), peer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(remotes)
|
Ok(remotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the git remote is configured for the `Repository`.
|
||||||
|
pub fn is_remote(repo: &git2::Repository, alias: &str) -> anyhow::Result<bool> {
|
||||||
|
match repo.find_remote(alias) {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(err) if err.code() == git2::ErrorCode::NotFound => Ok(false),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the repository's "rad" remote.
|
/// Get the repository's "rad" remote.
|
||||||
pub fn rad_remote(repo: &Repository) -> anyhow::Result<(git2::Remote, Id)> {
|
pub fn rad_remote(repo: &Repository) -> anyhow::Result<(git2::Remote, Id)> {
|
||||||
match radicle::rad::remote(repo) {
|
match radicle::rad::remote(repo) {
|
||||||
|
|
@ -204,6 +248,15 @@ pub fn rad_remote(repo: &Repository) -> anyhow::Result<(git2::Remote, Id)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_remote<'a>(
|
||||||
|
repo: &'a Repository,
|
||||||
|
name: &'a str,
|
||||||
|
url: &'a radicle::git::Url,
|
||||||
|
) -> anyhow::Result<Remote<'a>> {
|
||||||
|
let remote = repo.remote(name, &url.to_string())?;
|
||||||
|
Ok(Remote::try_from(remote)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Setup an upstream tracking branch for the given remote and branch.
|
/// Setup an upstream tracking branch for the given remote and branch.
|
||||||
/// Creates the tracking branch if it does not exist.
|
/// Creates the tracking branch if it does not exist.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,14 @@ pub fn rid(val: &OsString) -> anyhow::Result<Id> {
|
||||||
Id::from_str(&val).map_err(|_| anyhow!("invalid Repository ID '{}'", val))
|
Id::from_str(&val).map_err(|_| anyhow!("invalid Repository ID '{}'", val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pubkey(val: &OsString) -> anyhow::Result<NodeId> {
|
||||||
|
let Ok(did) = did(val) else {
|
||||||
|
let nid = nid(val)?;
|
||||||
|
return Ok(nid)
|
||||||
|
};
|
||||||
|
Ok(did.as_key().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addr(val: &OsString) -> anyhow::Result<Address> {
|
pub fn addr(val: &OsString) -> anyhow::Result<Address> {
|
||||||
let val = val.to_string_lossy();
|
let val = val.to_string_lossy();
|
||||||
Address::from_str(&val).map_err(|_| anyhow!("invalid address '{}'", val))
|
Address::from_str(&val).map_err(|_| anyhow!("invalid address '{}'", val))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue