From 8c7351c4c50517b3ccc3479f2a7a020bc607bf24 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 2 Oct 2022 15:05:39 +0800 Subject: [PATCH] support for `--url` for arbitrary urls when fetching (#450) Also known as 'anonymous remotes'. --- README.md | 1 + gitoxide-core/src/repository/fetch.rs | 3 +++ gitoxide-core/src/repository/remote.rs | 33 +++++++++++++++++--------- src/plumbing/main.rs | 2 ++ src/plumbing/options/mod.rs | 4 ++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6b6b6ac72d0..0e66e28b1f4 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Please see _'Development Status'_ for a listing of all crates and their capabili * **remote** * [x] **refs** - list all references available on the remote based on the current remote configuration. * [x] **ref-map** - show how remote references relate to their local tracking branches as mapped by refspecs. + * **fetch** - fetch the current remote or the given one, optionally just as dry-run. * **credential** * [x] **fill/approve/reject** - The same as `git credential`, but implemented in Rust, calling helpers only when from trusted configuration. * **free** - no git repository necessary diff --git a/gitoxide-core/src/repository/fetch.rs b/gitoxide-core/src/repository/fetch.rs index 163b1df6a2e..8a74c53002f 100644 --- a/gitoxide-core/src/repository/fetch.rs +++ b/gitoxide-core/src/repository/fetch.rs @@ -6,6 +6,7 @@ pub struct Options { pub format: OutputFormat, pub dry_run: bool, pub remote: Option, + pub url: Option, /// If non-empty, override all ref-specs otherwise configured in the remote pub ref_specs: Vec, } @@ -26,9 +27,11 @@ pub(crate) mod function { format, dry_run, remote, + url, ref_specs, }: Options, ) -> anyhow::Result<()> { + let _remote = crate::repository::remote::by_name_or_url(&repo, remote.as_deref(), url)?; todo!() } } diff --git a/gitoxide-core/src/repository/remote.rs b/gitoxide-core/src/repository/remote.rs index 39ee2ee0abc..e8f716472d1 100644 --- a/gitoxide-core/src/repository/remote.rs +++ b/gitoxide-core/src/repository/remote.rs @@ -1,5 +1,7 @@ #[cfg(any(feature = "blocking-client", feature = "async-client"))] mod refs_impl { + use super::by_name_or_url; + use crate::OutputFormat; use anyhow::bail; use git_repository as git; use git_repository::{ @@ -7,8 +9,6 @@ mod refs_impl { refspec::{match_group::validate::Fix, RefSpec}, }; - use crate::OutputFormat; - pub mod refs { use git_repository::bstr::BString; @@ -46,15 +46,7 @@ mod refs_impl { }: refs::Context, ) -> anyhow::Result<()> { use anyhow::Context; - let mut remote = match (name, url) { - (Some(name), None) => repo.find_remote(&name)?, - (None, None) => repo - .head()? - .into_remote(git::remote::Direction::Fetch) - .context("Cannot find a remote for unborn branch")??, - (None, Some(url)) => repo.remote_at(url)?, - (Some(_), Some(_)) => bail!("Must not set both the remote name and the url - they are mutually exclusive"), - }; + let mut remote = by_name_or_url(&repo, name.as_deref(), url)?; if let refs::Kind::Tracking { ref_specs, .. } = &kind { if format != OutputFormat::Human { bail!("JSON output isn't yet supported for listing ref-mappings."); @@ -258,3 +250,22 @@ mod refs_impl { } #[cfg(any(feature = "blocking-client", feature = "async-client"))] pub use refs_impl::{refs, refs_fn as refs, JsonRef}; + +use git_repository as git; + +pub(crate) fn by_name_or_url<'repo>( + repo: &'repo git::Repository, + name: Option<&str>, + url: Option, +) -> anyhow::Result> { + use anyhow::{bail, Context}; + Ok(match (name, url) { + (Some(name), None) => repo.find_remote(&name)?, + (None, None) => repo + .head()? + .into_remote(git::remote::Direction::Fetch) + .context("Cannot find a remote for unborn branch")??, + (None, Some(url)) => repo.remote_at(url)?, + (Some(_), Some(_)) => bail!("Must not set both the remote name and the url - they are mutually exclusive"), + }) +} diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 9759f27e27d..0f8302fd7c6 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -118,12 +118,14 @@ pub fn main() -> Result<()> { dry_run, remote, ref_spec, + url, }) => { let opts = core::repository::fetch::Options { format, dry_run, remote, ref_specs: ref_spec, + url, }; prepare_and_run( "fetch", diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 5f3e995938c..40b605d3f61 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -129,6 +129,10 @@ pub mod fetch { #[clap(long, short = 'r')] pub remote: Option, + /// Connect directly to the given URL, forgoing any configuration from the repository. + #[clap(long, short = 'u', conflicts_with("remote"), parse(try_from_os_str = std::convert::TryFrom::try_from))] + pub url: Option, + /// Override the built-in and configured ref-specs with one or more of the given ones. #[clap(parse(try_from_os_str = git::env::os_str_to_bstring))] pub ref_spec: Vec,