diff options
Diffstat (limited to 'vendor/gix/src/repository/remote.rs')
-rw-r--r-- | vendor/gix/src/repository/remote.rs | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/vendor/gix/src/repository/remote.rs b/vendor/gix/src/repository/remote.rs new file mode 100644 index 000000000..e3f210899 --- /dev/null +++ b/vendor/gix/src/repository/remote.rs @@ -0,0 +1,199 @@ +#![allow(clippy::result_large_err)] +use std::convert::TryInto; + +use crate::{bstr::BStr, config, remote, remote::find, Remote}; + +impl crate::Repository { + /// Create a new remote available at the given `url`. + /// + /// It's configured to fetch included tags by default, similar to git. + /// See [`with_fetch_tags(…)`][Remote::with_fetch_tags()] for a way to change it. + pub fn remote_at<Url, E>(&self, url: Url) -> Result<Remote<'_>, remote::init::Error> + where + Url: TryInto<gix_url::Url, Error = E>, + gix_url::parse::Error: From<E>, + { + Remote::from_fetch_url(url, true, self) + } + + /// Create a new remote available at the given `url` similarly to [`remote_at()`][crate::Repository::remote_at()], + /// but don't rewrite the url according to rewrite rules. + /// This eliminates a failure mode in case the rewritten URL is faulty, allowing to selectively [apply rewrite + /// rules][Remote::rewrite_urls()] later and do so non-destructively. + pub fn remote_at_without_url_rewrite<Url, E>(&self, url: Url) -> Result<Remote<'_>, remote::init::Error> + where + Url: TryInto<gix_url::Url, Error = E>, + gix_url::parse::Error: From<E>, + { + Remote::from_fetch_url(url, false, self) + } + + /// Find the remote with the given `name_or_url` or report an error, similar to [`try_find_remote(…)`][Self::try_find_remote()]. + /// + /// Note that we will obtain remotes only if we deem them [trustworthy][crate::open::Options::filter_config_section()]. + pub fn find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Result<Remote<'_>, find::existing::Error> { + let name_or_url = name_or_url.into(); + Ok(self + .try_find_remote(name_or_url) + .ok_or_else(|| find::existing::Error::NotFound { + name: name_or_url.into(), + })??) + } + + /// Find the default remote as configured, or `None` if no such configuration could be found. + /// + /// See [remote_default_name()][Self::remote_default_name()] for more information on the `direction` parameter. + pub fn find_default_remote( + &self, + direction: remote::Direction, + ) -> Option<Result<Remote<'_>, find::existing::Error>> { + self.remote_default_name(direction) + .map(|name| self.find_remote(name.as_ref())) + } + + /// Find the remote with the given `name_or_url` or return `None` if it doesn't exist, for the purpose of fetching or pushing + /// data to a remote. + /// + /// There are various error kinds related to partial information or incorrectly formatted URLs or ref-specs. + /// Also note that the created `Remote` may have neither fetch nor push ref-specs set at all. + /// + /// Note that ref-specs are de-duplicated right away which may change their order. This doesn't affect matching in any way + /// as negations/excludes are applied after includes. + /// + /// We will only include information if we deem it [trustworthy][crate::open::Options::filter_config_section()]. + pub fn try_find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Option<Result<Remote<'_>, find::Error>> { + self.try_find_remote_inner(name_or_url, true) + } + + /// Similar to [try_find_remote()][Self::try_find_remote()], but removes a failure mode if rewritten URLs turn out to be invalid + /// as it skips rewriting them. + /// Use this in conjunction with [`Remote::rewrite_urls()`] to non-destructively apply the rules and keep the failed urls unchanged. + pub fn try_find_remote_without_url_rewrite<'a>( + &self, + name_or_url: impl Into<&'a BStr>, + ) -> Option<Result<Remote<'_>, find::Error>> { + self.try_find_remote_inner(name_or_url, false) + } + + fn try_find_remote_inner<'a>( + &self, + name_or_url: impl Into<&'a BStr>, + rewrite_urls: bool, + ) -> Option<Result<Remote<'_>, find::Error>> { + fn config_spec<T: config::tree::keys::Validate>( + specs: Vec<std::borrow::Cow<'_, BStr>>, + name_or_url: &BStr, + key: &'static config::tree::keys::Any<T>, + op: gix_refspec::parse::Operation, + ) -> Result<Vec<gix_refspec::RefSpec>, find::Error> { + let kind = key.name; + specs + .into_iter() + .map(|spec| { + key.try_into_refspec(spec, op).map_err(|err| find::Error::RefSpec { + remote_name: name_or_url.into(), + kind, + source: err, + }) + }) + .collect::<Result<Vec<_>, _>>() + .map(|mut specs| { + specs.sort(); + specs.dedup(); + specs + }) + } + + let mut filter = self.filter_config_section(); + let name_or_url = name_or_url.into(); + let mut config_url = |key: &'static config::tree::keys::Url, kind: &'static str| { + self.config + .resolved + .string_filter("remote", Some(name_or_url), key.name, &mut filter) + .map(|url| { + key.try_into_url(url).map_err(|err| find::Error::Url { + kind, + remote_name: name_or_url.into(), + source: err, + }) + }) + }; + let url = config_url(&config::tree::Remote::URL, "fetch"); + let push_url = config_url(&config::tree::Remote::PUSH_URL, "push"); + let config = &self.config.resolved; + + let fetch_specs = config + .strings_filter("remote", Some(name_or_url), "fetch", &mut filter) + .map(|specs| { + config_spec( + specs, + name_or_url, + &config::tree::Remote::FETCH, + gix_refspec::parse::Operation::Fetch, + ) + }); + let push_specs = config + .strings_filter("remote", Some(name_or_url), "push", &mut filter) + .map(|specs| { + config_spec( + specs, + name_or_url, + &config::tree::Remote::PUSH, + gix_refspec::parse::Operation::Push, + ) + }); + let fetch_tags = config + .string_filter("remote", Some(name_or_url), "tagOpt", &mut filter) + .map(|value| { + config::tree::Remote::TAG_OPT + .try_into_tag_opt(value) + .map_err(Into::into) + }); + let fetch_tags = match fetch_tags { + Some(Ok(v)) => v, + Some(Err(err)) => return Some(Err(err)), + None => Default::default(), + }; + + match (url, fetch_specs, push_url, push_specs) { + (None, None, None, None) => None, + (None, _, None, _) => Some(Err(find::Error::UrlMissing)), + (url, fetch_specs, push_url, push_specs) => { + let url = match url { + Some(Ok(v)) => Some(v), + Some(Err(err)) => return Some(Err(err)), + None => None, + }; + let push_url = match push_url { + Some(Ok(v)) => Some(v), + Some(Err(err)) => return Some(Err(err)), + None => None, + }; + let fetch_specs = match fetch_specs { + Some(Ok(v)) => v, + Some(Err(err)) => return Some(Err(err)), + None => Vec::new(), + }; + let push_specs = match push_specs { + Some(Ok(v)) => v, + Some(Err(err)) => return Some(Err(err)), + None => Vec::new(), + }; + + Some( + Remote::from_preparsed_config( + Some(name_or_url.to_owned()), + url, + push_url, + fetch_specs, + push_specs, + rewrite_urls, + fetch_tags, + self, + ) + .map_err(Into::into), + ) + } + } + } +} |