summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/remote/url/rewrite.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/remote/url/rewrite.rs')
-rw-r--r--vendor/gix/src/remote/url/rewrite.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/vendor/gix/src/remote/url/rewrite.rs b/vendor/gix/src/remote/url/rewrite.rs
new file mode 100644
index 000000000..ae0eee426
--- /dev/null
+++ b/vendor/gix/src/remote/url/rewrite.rs
@@ -0,0 +1,100 @@
+use gix_features::threading::OwnShared;
+
+use crate::{
+ bstr::{BStr, BString, ByteVec},
+ config,
+ remote::Direction,
+};
+
+#[derive(Debug, Clone)]
+struct Replace {
+ find: BString,
+ with: OwnShared<BString>,
+}
+
+#[derive(Default, Debug, Clone)]
+pub(crate) struct Rewrite {
+ url_rewrite: Vec<Replace>,
+ push_url_rewrite: Vec<Replace>,
+}
+
+/// Init
+impl Rewrite {
+ pub fn from_config(
+ config: &gix_config::File<'static>,
+ mut filter: fn(&gix_config::file::Metadata) -> bool,
+ ) -> Rewrite {
+ config
+ .sections_by_name_and_filter("url", &mut filter)
+ .map(|sections| {
+ let mut url_rewrite = Vec::new();
+ let mut push_url_rewrite = Vec::new();
+ for section in sections {
+ let replace = match section.header().subsection_name() {
+ Some(base) => OwnShared::new(base.to_owned()),
+ None => continue,
+ };
+
+ for instead_of in section.values(config::tree::Url::INSTEAD_OF.name) {
+ url_rewrite.push(Replace {
+ with: OwnShared::clone(&replace),
+ find: instead_of.into_owned(),
+ });
+ }
+ for instead_of in section.values(config::tree::Url::PUSH_INSTEAD_OF.name) {
+ push_url_rewrite.push(Replace {
+ with: OwnShared::clone(&replace),
+ find: instead_of.into_owned(),
+ });
+ }
+ }
+ Rewrite {
+ url_rewrite,
+ push_url_rewrite,
+ }
+ })
+ .unwrap_or_default()
+ }
+}
+
+/// Access
+impl Rewrite {
+ fn replacements_for(&self, direction: Direction) -> &[Replace] {
+ match direction {
+ Direction::Fetch => &self.url_rewrite,
+ Direction::Push => &self.push_url_rewrite,
+ }
+ }
+
+ pub fn longest(&self, url: &gix_url::Url, direction: Direction) -> Option<BString> {
+ if self.replacements_for(direction).is_empty() {
+ None
+ } else {
+ let mut url = url.to_bstring();
+ self.rewrite_url_in_place(&mut url, direction).then_some(url)
+ }
+ }
+
+ /// Rewrite the given `url` of `direction` and return `true` if a replacement happened.
+ ///
+ /// Note that the result must still be checked for validity, it might not be a valid URL as we do a syntax-unaware replacement.
+ pub fn rewrite_url_in_place(&self, url: &mut BString, direction: Direction) -> bool {
+ self.replacements_for(direction)
+ .iter()
+ .fold(None::<(usize, &BStr)>, |mut acc, replace| {
+ if url.starts_with(replace.find.as_ref()) {
+ let (bytes_matched, prev_rewrite_with) =
+ acc.get_or_insert((replace.find.len(), replace.with.as_slice().into()));
+ if *bytes_matched < replace.find.len() {
+ *bytes_matched = replace.find.len();
+ *prev_rewrite_with = replace.with.as_slice().into();
+ }
+ };
+ acc
+ })
+ .map(|(bytes_matched, replace_with)| {
+ url.replace_range(..bytes_matched, replace_with);
+ })
+ .is_some()
+ }
+}