cli: Deduplicate RID Argument Handling
Multiple commands take an RID as a command line argument. However, the handling, which usually involves falling back to detection of the repository associated with the current directory, is duplicated many times over. Introduce `fn rid_or_cwd` which can be used by many commands.
This commit is contained in:
parent
f2e96c96ce
commit
bb97414a2d
|
|
@ -1,10 +1,11 @@
|
||||||
mod args;
|
mod args;
|
||||||
|
|
||||||
use anyhow::Context as _;
|
|
||||||
|
|
||||||
use radicle::rad;
|
use radicle::rad;
|
||||||
|
|
||||||
use crate::{terminal as term, warning};
|
use crate::{
|
||||||
|
terminal::{self as term, args::rid_or_cwd},
|
||||||
|
warning,
|
||||||
|
};
|
||||||
|
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
|
|
||||||
|
|
@ -13,15 +14,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let signer = profile.signer()?;
|
let signer = profile.signer()?;
|
||||||
let storage = &profile.storage;
|
let storage = &profile.storage;
|
||||||
|
let (_, rid) = rid_or_cwd(args.repo)?;
|
||||||
let rid = match args.repo {
|
|
||||||
Some(rid) => rid,
|
|
||||||
None => {
|
|
||||||
let (_, rid) = rad::cwd().context("Current directory is not a Radicle repository")?;
|
|
||||||
|
|
||||||
rid
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rad::fork(rid, &signer, &storage)?;
|
rad::fork(rid, &signer, &storage)?;
|
||||||
term::success!("Forked repository {rid} for {}", profile.id());
|
term::success!("Forked repository {rid} for {}", profile.id());
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use radicle_term::Element;
|
||||||
use crate::git::Rev;
|
use crate::git::Rev;
|
||||||
use crate::git::unified_diff::Encode as _;
|
use crate::git::unified_diff::Encode as _;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::Error;
|
use crate::terminal::args::{Error, rid_or_cwd};
|
||||||
use crate::terminal::format::Author;
|
use crate::terminal::format::Author;
|
||||||
use crate::terminal::patch::Message;
|
use crate::terminal::patch::Message;
|
||||||
|
|
||||||
|
|
@ -27,12 +27,7 @@ use args::Command;
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let storage = &profile.storage;
|
let storage = &profile.storage;
|
||||||
let rid = if let Some(rid) = args.repo {
|
let (_, rid) = rid_or_cwd(args.repo)?;
|
||||||
rid
|
|
||||||
} else {
|
|
||||||
let (_, rid) = radicle::rad::cwd()?;
|
|
||||||
rid
|
|
||||||
};
|
|
||||||
let repo = storage
|
let repo = storage
|
||||||
.repository(rid)
|
.repository(rid)
|
||||||
.context(anyhow!("repository `{rid}` not found in local storage"))?;
|
.context(anyhow!("repository `{rid}` not found in local storage"))?;
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ pub use args::Args;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
|
|
||||||
use localtime::LocalTime;
|
use localtime::LocalTime;
|
||||||
use radicle::cob::TypedId;
|
use radicle::cob::TypedId;
|
||||||
use radicle::git::BranchName;
|
use radicle::git::BranchName;
|
||||||
|
|
@ -23,6 +21,7 @@ use radicle::{Storage, cob, git};
|
||||||
use term::Element as _;
|
use term::Element as _;
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::rid_or_cwd;
|
||||||
use args::{ClearMode, Command, ListMode, SortBy};
|
use args::{ClearMode, Command, ListMode, SortBy};
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
@ -391,11 +390,8 @@ fn clear(notifs: &mut notifications::StoreWriter, mode: ClearMode) -> anyhow::Re
|
||||||
ClearMode::ByRepo(rid) => notifs.clear_by_repo(&rid)?,
|
ClearMode::ByRepo(rid) => notifs.clear_by_repo(&rid)?,
|
||||||
ClearMode::All => notifs.clear_all()?,
|
ClearMode::All => notifs.clear_all()?,
|
||||||
ClearMode::Contextual => {
|
ClearMode::Contextual => {
|
||||||
if let Ok((_, rid)) = radicle::rad::cwd() {
|
let (_, rid) = rid_or_cwd(None)?;
|
||||||
notifs.clear_by_repo(&rid)?
|
notifs.clear_by_repo(&rid)?
|
||||||
} else {
|
|
||||||
return Err(anyhow!("not a radicle repository"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if cleared > 0 {
|
if cleared > 0 {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ use crate::git::Rev;
|
||||||
use crate::node;
|
use crate::node;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::Element;
|
use crate::terminal::Element;
|
||||||
use crate::terminal::args::Error;
|
use crate::terminal::args::{Error, rid_or_cwd};
|
||||||
use crate::terminal::format::Author;
|
use crate::terminal::format::Author;
|
||||||
use crate::terminal::issue::Format;
|
use crate::terminal::issue::Format;
|
||||||
|
|
||||||
|
|
@ -34,11 +34,7 @@ const ABOUT: &str = "Manage issues";
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let rid = match args.repo {
|
let (_, rid) = rid_or_cwd(args.repo)?;
|
||||||
Some(rid) => rid,
|
|
||||||
None => radicle::rad::cwd().map(|(_, rid)| rid)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let repo = profile.storage.repository_mut(rid)?;
|
let repo = profile.storage.repository_mut(rid)?;
|
||||||
|
|
||||||
// Fallback to [`Command::List`] if no subcommand is provided.
|
// Fallback to [`Command::List`] if no subcommand is provided.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use radicle::{Node, prelude::*};
|
||||||
use crate::git::Rev;
|
use crate::git::Rev;
|
||||||
use crate::node;
|
use crate::node;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::rid_or_cwd;
|
||||||
use crate::terminal::patch::Message;
|
use crate::terminal::patch::Message;
|
||||||
|
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
|
|
@ -37,14 +38,7 @@ pub use args::Args;
|
||||||
use args::{AssignArgs, Command, CommentAction, LabelArgs};
|
use args::{AssignArgs, Command, CommentAction, LabelArgs};
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let (workdir, rid) = if let Some(rid) = args.repo {
|
let (workdir, rid) = rid_or_cwd(args.repo)?;
|
||||||
(None, rid)
|
|
||||||
} else {
|
|
||||||
radicle::rad::cwd()
|
|
||||||
.map(|(workdir, rid)| (Some(workdir), rid))
|
|
||||||
.map_err(|_| anyhow!("this command must be run in the context of a repository"))?
|
|
||||||
};
|
|
||||||
|
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let repository = profile.storage.repository(rid)?;
|
let repository = profile.storage.repository(rid)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
mod args;
|
mod args;
|
||||||
|
|
||||||
use anyhow::{Context as _, anyhow};
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use radicle::cob;
|
use radicle::cob;
|
||||||
use radicle::identity::{Identity, Visibility};
|
use radicle::identity::{Identity, Visibility};
|
||||||
|
|
@ -8,17 +8,13 @@ use radicle::node::Handle as _;
|
||||||
use radicle::storage::{SignRepository, ValidateRepository, WriteRepository, WriteStorage};
|
use radicle::storage::{SignRepository, ValidateRepository, WriteRepository, WriteStorage};
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::rid_or_cwd;
|
||||||
|
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let rid = match args.repo {
|
let (_, rid) = rid_or_cwd(args.repo)?;
|
||||||
Some(rid) => rid,
|
|
||||||
None => radicle::rad::cwd()
|
|
||||||
.map(|(_, rid)| rid)
|
|
||||||
.context("Current directory is not a Radicle repository")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let repo = profile.storage.repository_mut(rid)?;
|
let repo = profile.storage.repository_mut(rid)?;
|
||||||
let signer = profile.signer()?;
|
let signer = profile.signer()?;
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,19 @@ pub mod rm;
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
|
|
||||||
use radicle::storage::ReadStorage;
|
use radicle::storage::ReadStorage;
|
||||||
|
|
||||||
use crate::terminal as term;
|
|
||||||
use crate::terminal::Context;
|
use crate::terminal::Context;
|
||||||
|
use crate::terminal::{self as term, args::rid_or_cwd};
|
||||||
|
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
use args::{Command, ListOption};
|
use args::{Command, ListOption};
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl Context) -> anyhow::Result<()> {
|
||||||
let (working, rid) = radicle::rad::cwd()
|
let (Some(working), rid) = rid_or_cwd(None)? else {
|
||||||
.map_err(|_| anyhow!("this command must be run in the context of a repository"))?;
|
anyhow::bail!("this command must be run in the context of a repository");
|
||||||
|
};
|
||||||
|
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let command = args
|
let command = args
|
||||||
.command
|
.command
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::collections::BTreeMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
use anyhow::{Context as _, anyhow};
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use radicle::node;
|
use radicle::node;
|
||||||
use radicle::node::SyncedAt;
|
use radicle::node::SyncedAt;
|
||||||
|
|
@ -22,6 +22,7 @@ use radicle_term::Element;
|
||||||
use crate::node::SyncReporting;
|
use crate::node::SyncReporting;
|
||||||
use crate::node::SyncSettings;
|
use crate::node::SyncSettings;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::rid_or_cwd;
|
||||||
use crate::terminal::format::Author;
|
use crate::terminal::format::Author;
|
||||||
use crate::terminal::{Table, TableOptions};
|
use crate::terminal::{Table, TableOptions};
|
||||||
|
|
||||||
|
|
@ -41,14 +42,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Some(Command::Status { repo, sort_by }) => {
|
Some(Command::Status { repo, sort_by }) => {
|
||||||
let rid = match repo {
|
let (_, rid) = rid_or_cwd(repo)?;
|
||||||
Some(rid) => rid,
|
|
||||||
None => {
|
|
||||||
let (_, rid) = radicle::rad::cwd()
|
|
||||||
.context("Current directory is not a Radicle repository")?;
|
|
||||||
rid
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sync_status(rid, &mut node, &profile, &sort_by, verbose)?;
|
sync_status(rid, &mut node, &profile, &sort_by, verbose)?;
|
||||||
}
|
}
|
||||||
None => match SyncMode::from(args.sync) {
|
None => match SyncMode::from(args.sync) {
|
||||||
|
|
@ -57,14 +51,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
settings,
|
settings,
|
||||||
direction,
|
direction,
|
||||||
} => {
|
} => {
|
||||||
let rid = match repo {
|
let (_, rid) = rid_or_cwd(repo)?;
|
||||||
Some(rid) => rid,
|
|
||||||
None => {
|
|
||||||
let (_, rid) = radicle::rad::cwd()
|
|
||||||
.context("Current directory is not a Radicle repository")?;
|
|
||||||
rid
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let settings = settings.clone().with_profile(&profile);
|
let settings = settings.clone().with_profile(&profile);
|
||||||
|
|
||||||
if matches!(direction, SyncDirection::Fetch | SyncDirection::Both) {
|
if matches!(direction, SyncDirection::Fetch | SyncDirection::Both) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ mod args;
|
||||||
|
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
|
|
||||||
use anyhow::{Context as _, anyhow};
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
use radicle::git::raw::ErrorExt as _;
|
use radicle::git::raw::ErrorExt as _;
|
||||||
|
|
@ -10,6 +10,7 @@ use radicle::prelude::NodeId;
|
||||||
use radicle::storage::{ReadRepository, ReadStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::rid_or_cwd;
|
||||||
|
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
|
|
||||||
|
|
@ -21,14 +22,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
.qualified()
|
.qualified()
|
||||||
.ok_or_else(|| anyhow!("reference must be fully-qualified, eg. 'refs/heads/master'"))?;
|
.ok_or_else(|| anyhow!("reference must be fully-qualified, eg. 'refs/heads/master'"))?;
|
||||||
let nid = args.node.unwrap_or(profile.public_key);
|
let nid = args.node.unwrap_or(profile.public_key);
|
||||||
let rid = match args.repo {
|
let (_, rid) = rid_or_cwd(args.repo)?;
|
||||||
Some(rid) => rid,
|
|
||||||
None => {
|
|
||||||
let (_, rid) =
|
|
||||||
radicle::rad::cwd().context("Current directory is not a Radicle repository")?;
|
|
||||||
rid
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let repo = storage.repository(rid)?;
|
let repo = storage.repository(rid)?;
|
||||||
let now = time::SystemTime::now();
|
let now = time::SystemTime::now();
|
||||||
let timeout = args.timeout();
|
let timeout = args.timeout();
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,34 @@ impl TypedValueParser for ScopeParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A wrapper around [`radicle::rad::cwd`] that should be preferred over direct
|
||||||
|
/// calls in this crate.
|
||||||
|
///
|
||||||
|
/// If the given [`Option<RepoId>`] is `Some`, it is returned as is.
|
||||||
|
/// No attempt is made to detect whether the current working directory is
|
||||||
|
/// a Radicle repository (therefore it is also not checked whether the given
|
||||||
|
/// [`RepoId`] matches the [`RepoId`] associated with the current working
|
||||||
|
/// directory), and the returned repository is `None`.
|
||||||
|
///
|
||||||
|
/// Otherwise, i.e, if the given [`Option<RepoId>`] is `None`, an attempt is
|
||||||
|
/// made to detect the [`RepoId`] associated with the current working directory,
|
||||||
|
/// by calling [`radicle::rad::cwd`]. If this detection fails, an error with
|
||||||
|
/// context is returned.
|
||||||
|
pub(crate) fn rid_or_cwd(
|
||||||
|
rid: Option<RepoId>,
|
||||||
|
) -> anyhow::Result<(Option<radicle::git::raw::Repository>, RepoId)> {
|
||||||
|
match rid {
|
||||||
|
Some(rid) => Ok((None, rid)),
|
||||||
|
None => {
|
||||||
|
use anyhow::Context as _;
|
||||||
|
|
||||||
|
let (repository, rid) =
|
||||||
|
radicle::rad::cwd().context("Current directory is not a Radicle repository")?;
|
||||||
|
Ok((Some(repository), rid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue