use miette::{Context, IntoDiagnostic};
use url::Url;
use crate::actions::GlobalArgs;
use crate::render::spinner::spin_until_ready;
use crate::render::ui::confirm_with_prompt;
use crate::types::context::BergContext;
use crate::types::git::{Git, MaybeOwnerRepo, OwnerRepo};
use clap::Parser;
#[derive(Parser, Debug)]
pub struct RepoCloneArgs {
#[arg(value_name = "REPO or OWNER/REPO")]
pub owner_and_repo: MaybeOwnerRepo,
#[arg(long, default_value_t = false)]
pub use_ssh: bool,
#[arg(value_name = "DESTINATION")]
pub destination: Option<String>,
}
impl RepoCloneArgs {
pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
let _ = global_args;
let ctx = BergContext::new(self, global_args.clone()).await?;
let owner_repo = match ctx.args.owner_and_repo {
MaybeOwnerRepo::ImplicitOwner(ref repo) => {
let owner = ctx
.client
.user_get_current()
.await
.into_diagnostic()?
.login
.context("Current user has no username on targeted forgejo instance")?;
OwnerRepo {
owner,
repo: repo.clone(),
}
}
MaybeOwnerRepo::ExplicitOwner(ref owner_repo) => owner_repo.clone(),
};
let url = if ctx.args.use_ssh {
spin_until_ready(get_ssh_url(
&ctx,
owner_repo.owner.as_str(),
owner_repo.repo.as_str(),
))
.await?
} else {
ctx.config
.url()?
.join(format!("/{owner_repo}.git").as_str())
.into_diagnostic()?
};
println!("Cloning {url} ...");
if !global_args.non_interactive
&& !confirm_with_prompt(format!(
"Do you want to clone the repository '{owner_repo}' into {pwd}/{repo}",
pwd = std::env::current_dir().into_diagnostic()?.display(),
repo = owner_repo.repo
))?
{
println!("Canceled clone!");
std::process::exit(0);
}
Git::clone(
url,
ctx.args.destination.unwrap_or(owner_repo.repo).as_str(),
)?;
Ok(())
}
}
async fn get_ssh_url(
ctx: &BergContext<RepoCloneArgs>,
ownername: &str,
reponame: &str,
) -> miette::Result<Url> {
ctx.client
.repo_get(ownername, reponame)
.await
.into_diagnostic()
.inspect(|x| tracing::debug!("{x:#?}"))
.and_then(|repo| repo.ssh_url.context("No SSH url on repo"))
.and_then(|url| {
Url::parse(url.as_str())
.into_diagnostic()
.with_context(|| format!("Url wasn't a valid SSH Url: {url}", url = url.as_str()))
})
.context("User doesn't own the repo that was specified or at least doesn't have access'.")
}