#![allow(
clippy::case_sensitive_file_extension_comparisons,
clippy::missing_const_for_fn,
clippy::use_self,
clippy::unwrap_used
)]
#![cfg_attr(dylint_lib = "collapsible_unwrap", allow(collapsible_unwrap))]
#![cfg_attr(
dylint_lib = "inconsistent_qualification",
allow(inconsistent_qualification)
)]
use anyhow::Result as CargoResult;
use std::hash::{self, Hash};
use url::Url;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CanonicalUrl(Url);
impl CanonicalUrl {
pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {
let mut url = url.clone();
if url.cannot_be_a_base() {
anyhow::bail!("invalid url `{url}`: cannot-be-a-base-URLs are not supported")
}
if url.path().ends_with('/') {
url.path_segments_mut().unwrap().pop_if_empty();
}
if url.host_str() == Some("github.com") {
url = format!("https{}", &url[url::Position::AfterScheme..])
.parse()
.unwrap();
let path = url.path().to_lowercase();
url.set_path(&path);
}
let needs_chopping = url.path().ends_with(".git");
if needs_chopping {
let last = {
let last = url.path_segments().unwrap().next_back().unwrap();
last[..last.len() - 4].to_owned()
};
url.path_segments_mut().unwrap().pop().push(&last);
}
Ok(CanonicalUrl(url))
}
pub fn raw_canonicalized_url(&self) -> &Url {
&self.0
}
}
impl Hash for CanonicalUrl {
fn hash<S: hash::Hasher>(&self, into: &mut S) {
self.0.as_str().hash(into);
}
}