diff --git a/radicle-cli/examples/rad-rm.md b/radicle-cli/examples/rad-rm.md index b484b4c5..661ac6c5 100644 --- a/radicle-cli/examples/rad-rm.md +++ b/radicle-cli/examples/rad-rm.md @@ -11,6 +11,7 @@ Now let's delete the `heartwood` project: ``` $ rad rm rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --no-confirm ✓ Untracked rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji +✓ Successfully removed 'rad' remote ✓ Successfully removed rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from storage ``` diff --git a/radicle-cli/src/commands/rm.rs b/radicle-cli/src/commands/rm.rs index e07ab5fb..b010f829 100644 --- a/radicle-cli/src/commands/rm.rs +++ b/radicle-cli/src/commands/rm.rs @@ -6,8 +6,10 @@ use anyhow::anyhow; use radicle::identity::Id; use radicle::node; use radicle::node::Handle as _; +use radicle::storage; use radicle::Profile; +use crate::git; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; @@ -71,7 +73,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let profile = ctx.profile()?; let storage = &profile.storage; let rid = options.rid; - let path = radicle::storage::git::paths::repository(storage, &rid); + let path = storage::git::paths::repository(storage, &rid); if !path.exists() { anyhow::bail!("repository {rid} was not found"); @@ -79,6 +81,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { if !options.confirm || term::confirm(format!("Remove {rid}?")) { untrack(&rid, &profile)?; + remove_remote(&rid)?; fs::remove_dir_all(path)?; term::success!("Successfully removed {rid} from storage"); } @@ -106,3 +109,20 @@ fn untrack(rid: &Id, profile: &Profile) -> anyhow::Result<()> { Ok(()) } + +fn remove_remote(rid: &Id) -> anyhow::Result<()> { + let cwd = std::env::current_dir()?; + if let Err(e) = git::Repository::open(cwd) + .map_err(|err| err.into()) + .and_then(|repo| git::remove_remote(&repo, rid)) + { + term::warning(&format!( + "Attempted to remove 'rad' remote from working copy: {e}" + )); + term::warning("In case a working copy exists, make sure to `git remote remove rad`"); + } else { + term::success!("Successfully removed 'rad' remote"); + } + + Ok(()) +} diff --git a/radicle-cli/src/git.rs b/radicle-cli/src/git.rs index 26a94617..c7aed975 100644 --- a/radicle-cli/src/git.rs +++ b/radicle-cli/src/git.rs @@ -251,6 +251,28 @@ pub fn rad_remote(repo: &Repository) -> anyhow::Result<(git2::Remote, Id)> { } } +pub fn remove_remote(repo: &Repository, rid: &Id) -> anyhow::Result<()> { + // N.b. ensure that we are removing the remote for the correct RID + match radicle::rad::remote(repo) { + Ok((_, rid_)) => { + if rid_ != *rid { + return Err(radicle::rad::RemoteError::RidMismatch { + found: rid_, + expected: *rid, + } + .into()); + } + } + Err(radicle::rad::RemoteError::NotFound(_)) => return Ok(()), + Err(err) => return Err(err).context("could not read git remote configuration"), + }; + + match radicle::rad::remove_remote(repo) { + Ok(()) => Ok(()), + Err(err) => Err(err).context("could not read git remote configuration"), + } +} + pub fn add_remote<'a>( repo: &'a Repository, name: &'a str, diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index e27b9ab5..ee9a83f7 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -265,6 +265,8 @@ pub enum RemoteError { InvalidUtf8, #[error("remote `{0}` not found")] NotFound(String), + #[error("expected remote for {expected} but found {found}")] + RidMismatch { found: Id, expected: Id }, } /// Get the radicle ("rad") remote of a repository, and return the associated project id. @@ -282,6 +284,18 @@ pub fn remote(repo: &git2::Repository) -> Result<(git2::Remote<'_>, Id), RemoteE Ok((remote, url.repo)) } +/// Delete the radicle ("rad") remote of a repository. +pub fn remove_remote(repo: &git2::Repository) -> Result<(), RemoteError> { + repo.remote_delete(&REMOTE_NAME).map_err(|e| { + if e.code() == git2::ErrorCode::NotFound { + RemoteError::NotFound(REMOTE_NAME.to_string()) + } else { + RemoteError::from(e) + } + })?; + Ok(()) +} + /// Get the Id of project in current working directory pub fn cwd() -> Result<(git2::Repository, Id), RemoteError> { let repo = git2::Repository::open(Path::new("."))?;