|
| 1 | +use url::Url; |
| 2 | + |
| 3 | +use pep508_rs::VerbatimUrl; |
| 4 | + |
| 5 | +/// Given a [`VerbatimUrl`] and a redirect, apply the redirect to the URL while preserving as much |
| 6 | +/// of the verbatim representation as possible. |
| 7 | +pub(crate) fn apply_redirect(url: &VerbatimUrl, redirect: &Url) -> VerbatimUrl { |
| 8 | + let redirect = VerbatimUrl::from_url(redirect.clone()); |
| 9 | + |
| 10 | + // The redirect should be the "same" URL, but with a specific commit hash added after the `@`. |
| 11 | + // We take advantage of this to preserve as much of the verbatim representation as possible. |
| 12 | + if let Some(given) = url.given() { |
| 13 | + if let Some(precise_suffix) = redirect |
| 14 | + .raw() |
| 15 | + .path() |
| 16 | + .rsplit_once('@') |
| 17 | + .map(|(_, suffix)| suffix.to_owned()) |
| 18 | + { |
| 19 | + // If there was an `@` in the original representation... |
| 20 | + if let Some((.., parsed_suffix)) = url.raw().path().rsplit_once('@') { |
| 21 | + if let Some((given_prefix, given_suffix)) = given.rsplit_once('@') { |
| 22 | + // And the portion after the `@` is stable between the parsed and given representations... |
| 23 | + if given_suffix == parsed_suffix { |
| 24 | + // Preserve everything that precedes the `@` in the precise representation. |
| 25 | + return redirect.with_given(format!("{given_prefix}@{precise_suffix}")); |
| 26 | + } |
| 27 | + } |
| 28 | + } else { |
| 29 | + // If there was no `@` in the original representation, we can just append the |
| 30 | + // precise suffix to the given representation. |
| 31 | + return redirect.with_given(format!("{given}@{precise_suffix}")); |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + redirect |
| 37 | +} |
| 38 | + |
| 39 | +#[cfg(test)] |
| 40 | +mod tests { |
| 41 | + use super::*; |
| 42 | + |
| 43 | + #[test] |
| 44 | + fn test_apply_redirect() -> Result<(), url::ParseError> { |
| 45 | + // If there's no `@` in the original representation, we can just append the precise suffix |
| 46 | + // to the given representation. |
| 47 | + let verbatim = VerbatimUrl::parse("https://github.com/flask.git")? |
| 48 | + .with_given("git+https://github.com/flask.git"); |
| 49 | + let redirect = |
| 50 | + Url::parse("https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe")?; |
| 51 | + |
| 52 | + let expected = VerbatimUrl::parse( |
| 53 | + "https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe", |
| 54 | + )? |
| 55 | + .with_given("https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe"); |
| 56 | + assert_eq!(apply_redirect(&verbatim, &redirect), expected); |
| 57 | + |
| 58 | + // If there's an `@` in the original representation, and it's stable between the parsed and |
| 59 | + // given representations, we preserve everything that precedes the `@` in the precise |
| 60 | + // representation. |
| 61 | + let verbatim = VerbatimUrl::parse("https://github.com/flask.git@main")? |
| 62 | + .with_given("git+https://${DOMAIN}.com/flask.git@main"); |
| 63 | + let redirect = |
| 64 | + Url::parse("https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe")?; |
| 65 | + |
| 66 | + let expected = VerbatimUrl::parse( |
| 67 | + "https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe", |
| 68 | + )? |
| 69 | + .with_given("https://${DOMAIN}.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe"); |
| 70 | + assert_eq!(apply_redirect(&verbatim, &redirect), expected); |
| 71 | + |
| 72 | + // If there's a conflict after the `@`, discard the original representation. |
| 73 | + let verbatim = VerbatimUrl::parse("https://github.com/flask.git@main")? |
| 74 | + .with_given("git+https://github.com/flask.git@${TAG}".to_string()); |
| 75 | + let redirect = |
| 76 | + Url::parse("https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe")?; |
| 77 | + |
| 78 | + let expected = VerbatimUrl::parse( |
| 79 | + "https://github.com/flask.git@b90a4f1f4a370e92054b9cc9db0efcb864f87ebe", |
| 80 | + )?; |
| 81 | + assert_eq!(apply_redirect(&verbatim, &redirect), expected); |
| 82 | + |
| 83 | + Ok(()) |
| 84 | + } |
| 85 | +} |
0 commit comments