use crate::remote::find; use crate::{remote, Remote}; use std::convert::TryInto; impl crate::Repository { /// Create a new remote available at the given `url`. pub fn remote_at(&self, url: Url) -> Result, remote::init::Error> where Url: TryInto, git_url::parse::Error: From, { Remote::from_fetch_url(url, true, self) } /// Create a new remote available at the given `url`, 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(&self, url: Url) -> Result, remote::init::Error> where Url: TryInto, git_url::parse::Error: From, { Remote::from_fetch_url(url, false, self) } /// Find the remote with the given `name` or report an error, similar to [`try_find_remote(…)`][Self::try_find_remote()]. /// /// Note that we will include remotes only if we deem them [trustworthy][crate::open::Options::filter_config_section()]. pub fn find_remote(&self, name: &str) -> Result, find::existing::Error> { Ok(self .try_find_remote(name) .ok_or_else(|| find::existing::Error::NotFound { name: name.into() })??) } /// Find the remote with the given `name` 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(&self, name: &str) -> Option, find::Error>> { self.try_find_remote_inner(name, 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(&self, name: &str) -> Option, find::Error>> { self.try_find_remote_inner(name, false) } fn try_find_remote_inner(&self, name: &str, rewrite_urls: bool) -> Option, find::Error>> { let mut filter = self.filter_config_section(); let mut config_url = |field: &str, kind: &'static str| { self.config .resolved .string_filter("remote", name.into(), field, &mut filter) .map(|url| { git_url::parse::parse(url.as_ref()).map_err(|err| find::Error::Url { kind, url: url.into_owned(), source: err, }) }) }; let url = config_url("url", "fetch"); let push_url = config_url("pushUrl", "push"); let mut config_spec = |op: git_refspec::parse::Operation| { let kind = match op { git_refspec::parse::Operation::Fetch => "fetch", git_refspec::parse::Operation::Push => "push", }; self.config .resolved .strings_filter("remote", name.into(), kind, &mut filter) .map(|specs| { specs .into_iter() .map(|spec| { git_refspec::parse(spec.as_ref(), op) .map(|spec| spec.to_owned()) .map_err(|err| find::Error::RefSpec { spec: spec.into_owned(), kind, source: err, }) }) .collect::, _>>() .map(|mut specs| { specs.sort(); specs.dedup(); specs }) }) }; let fetch_specs = config_spec(git_refspec::parse::Operation::Fetch); let push_specs = config_spec(git_refspec::parse::Operation::Push); 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( name.to_owned().into(), url, push_url, fetch_specs, push_specs, rewrite_urls, self, ) .map_err(Into::into), ) } } } }