190 lines · 7.6 KB · Rust
RawDownload
use gix_refspec::RefSpec; #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]use crate::types::RemoteDetached;use crate::{Remote, bstr::BStr, remote}; /// Accessimpl<'repo> Remote<'repo> {    /// Return the name of this remote or `None` if it wasn't persisted to disk yet.    pub fn name(&self) -> Option<&remote::Name<'static>> {        self.name.as_ref()    }     /// Return our repository reference.    pub fn repo(&self) -> &'repo crate::Repository {        self.repo    }     /// Return the set of ref-specs used for `direction`, which may be empty, in order of occurrence in the configuration.    pub fn refspecs(&self, direction: remote::Direction) -> &[RefSpec] {        match direction {            remote::Direction::Fetch => &self.fetch_specs,            remote::Direction::Push => &self.push_specs,        }    }     /// Return how we handle tags when fetching the remote.    pub fn fetch_tags(&self) -> remote::fetch::Tags {        self.fetch_tags    }     /// Return the first url used for the given `direction` with rewrites from `url.<base>.insteadOf|pushInsteadOf`, unless the instance    /// was created with one of the `_without_url_rewrite()` methods.    /// See [`urls()`](Self::urls()) for how rewrite rules differ between fetch URLs, explicit push URLs, and push fallbacks.    /// For pushing, this is the first `remote.<name>.pushUrl` or the first `remote.<name>.url` used for fetching, and for    /// fetching it's the first `remote.<name>.url`. Unlike `git remote get-url`, a missing fetch URL doesn't fall back to a    /// symbolic remote name, but a URL-shaped remote name may itself be used as the fallback URL.    /// Note that it's possible to only have the push url set, in which case there will be no way to fetch from the remote as    /// the push-url isn't used for that.    pub fn url(&self, direction: remote::Direction) -> Option<&gix_url::Url> {        self.urls(direction).next()    }     /// Return all urls used for the given `direction` with rewrites from `url.<base>.insteadOf|pushInsteadOf`, unless the    /// instance was created with one of the `_without_url_rewrite()` methods.    ///    /// Fetch URLs are rewritten with `url.<base>.insteadOf`. Explicit `remote.<name>.pushUrl` values are also rewritten with    /// `insteadOf`, and `pushInsteadOf` is ignored for them. If no explicit push URL is configured, the fetch URLs are used    /// as push fallbacks: matching `pushInsteadOf` rules take precedence, with `insteadOf` used when none match.    ///    /// Values are returned in configuration order.    pub fn urls(&self, direction: remote::Direction) -> impl Iterator<Item = &gix_url::Url> + '_ {        let (urls, aliases) = self.urls_and_aliases(direction);        debug_assert_eq!(            urls.len(),            aliases.len(),            "each URL should have a corresponding rewrite slot"        );        urls.iter()            .zip(aliases)            .map(|(url, alias)| alias.as_ref().unwrap_or(url))    }     fn urls_and_aliases(&self, direction: remote::Direction) -> (&[gix_url::Url], &[Option<gix_url::Url>]) {        match direction {            remote::Direction::Fetch => (&self.urls, &self.url_aliases),            remote::Direction::Push if self.push_urls.is_empty() => (&self.urls, &self.url_push_aliases),            remote::Direction::Push => (&self.push_urls, &self.push_url_aliases),        }    }     /// Return a clone of this remote without its repository reference.    #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]    pub(crate) fn detached(&self) -> RemoteDetached {        self.clone().into()    }} /// Access#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]impl RemoteDetached {    /// Return the name of this remote or `None` if it wasn't persisted to disk yet.    pub(crate) fn name(&self) -> Option<&remote::Name<'static>> {        self.name.as_ref()    }     /// Return the set of ref-specs used for fetching, which may be empty, in order of occurrence in the configuration.    pub(crate) fn fetch_refspecs(&self) -> &[RefSpec] {        &self.fetch_specs    }} /// Modificationimpl Remote<'_> {    /// Re-read `url.<base>.insteadOf|pushInsteadOf` and recompute the effective URLs returned by [`url()`](Self::url()) and    /// [`urls()`](Self::urls()). This may be called repeatedly to refresh rewrite rules after configuration changes.    ///    /// Every URL is attempted non-destructively: successful rewrites remain effective if another rewritten URL is malformed,    /// while a failed entry keeps using its original URL. The first error is returned in fetch, push-fallback, explicit-push    /// order. See [`urls()`](Self::urls()) for which rules apply to each category.    pub fn rewrite_urls(&mut self) -> Result<&mut Self, remote::init::Error> {        let (url_aliases, url_err) =            remote::init::rewrite_url_aliases_non_destructive(&self.repo.config, &self.urls, remote::Direction::Fetch);        self.url_aliases = url_aliases;        let url_push_err = if self.push_urls.is_empty() {            let (url_push_aliases, err) = remote::init::rewrite_url_aliases_with_fallback_non_destructive(                &self.repo.config,                &self.urls,                remote::Direction::Push,                remote::Direction::Fetch,            );            self.url_push_aliases = url_push_aliases;            err        } else {            self.url_push_aliases = vec![None; self.urls.len()];            None        };        let (push_url_aliases, push_url_err) = remote::init::rewrite_url_aliases_non_destructive_with_error_kind(            &self.repo.config,            &self.push_urls,            remote::Direction::Fetch,            remote::Direction::Push,        );        self.push_url_aliases = push_url_aliases;        url_err            .or(url_push_err)            .or(push_url_err)            .map(Err::<&mut Self, _>)            .transpose()?;        Ok(self)    }     /// Replace all currently set refspecs, typically from configuration, with the given `specs` for `direction`,    /// or `None` if one of the input specs could not be parsed.    pub fn replace_refspecs<Spec>(        &mut self,        specs: impl IntoIterator<Item = Spec>,        direction: remote::Direction,    ) -> Result<(), gix_refspec::parse::Error>    where        Spec: AsRef<BStr>,    {        use remote::Direction::*;        let specs: Vec<_> = specs            .into_iter()            .map(|spec| {                gix_refspec::parse(                    spec.as_ref(),                    match direction {                        Push => gix_refspec::parse::Operation::Push,                        Fetch => gix_refspec::parse::Operation::Fetch,                    },                )                .map(|url| url.to_owned())            })            .collect::<Result<_, _>>()?;        let dst = match direction {            Push => &mut self.push_specs,            Fetch => &mut self.fetch_specs,        };        *dst = specs;        Ok(())    }} #[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]impl From<Remote<'_>> for RemoteDetached {    fn from(        Remote {            name,            urls,            url_aliases,            url_push_aliases: _,            fetch_specs,            fetch_tags,            push_urls: _,            push_url_aliases: _,            push_specs: _,            repo: _,        }: Remote<'_>,    ) -> Self {        RemoteDetached {            name,            urls,            url_aliases,            fetch_specs,            fetch_tags,        }    }}