auto merge of #123 : alexcrichton/cargo/canonicalize-github-urls, r=wycats

In addition to canonicalizing checkout locations, this canonicalizes packages
for the resolver. This allows two dependencies with slightly different urls
pointing to the same repository to resolve to the same location and package.

Closes #104
This commit is contained in:
bors 2014-07-05 23:59:58 +00:00
commit 83590e2d41
3 changed files with 55 additions and 4 deletions

View file

@ -6,6 +6,7 @@ use url::Url;
use core::{Summary, Package, PackageId};
use sources::{PathSource, GitSource};
use sources::git;
use util::{Config, CargoResult};
use util::errors::human;
@ -61,7 +62,7 @@ pub enum Location {
Remote(Url),
}
#[deriving(Clone, PartialEq, Eq)]
#[deriving(Clone, Eq)]
pub struct SourceId {
pub kind: SourceKind,
pub location: Location,
@ -110,6 +111,25 @@ impl Show for SourceId {
}
}
// This custom implementation handles situations such as when two git sources
// point at *almost* the same URL, but not quite, even when they actually point
// to the same repository.
impl PartialEq for SourceId {
fn eq(&self, other: &SourceId) -> bool {
if self.kind != other.kind { return false }
if self.location == other.location { return true }
match (&self.kind, &other.kind, &self.location, &other.location) {
(&GitKind(..), &GitKind(..),
&Remote(ref u1), &Remote(ref u2)) => {
git::canonicalize_url(u1.to_str().as_slice()) ==
git::canonicalize_url(u2.to_str().as_slice())
}
_ => false,
}
}
}
impl SourceId {
pub fn new(kind: SourceKind, location: Location) -> SourceId {
SourceId { kind: kind, location: location }
@ -214,3 +234,22 @@ impl Source for SourceSet {
return Ok(ret);
}
}
#[cfg(test)]
mod tests {
use super::{SourceId, Remote, GitKind};
#[test]
fn github_sources_equal() {
let loc = Remote(from_str("https://github.com/foo/bar").unwrap());
let s1 = SourceId::new(GitKind("master".to_string()), loc);
let loc = Remote(from_str("git://github.com/foo/bar").unwrap());
let mut s2 = SourceId::new(GitKind("master".to_string()), loc);
assert_eq!(s1, s2);
s2.kind = GitKind("foo".to_string());
assert!(s1 != s2);
}
}

View file

@ -1,4 +1,4 @@
pub use self::utils::{GitRemote,GitDatabase,GitCheckout};
pub use self::source::{GitSource};
pub use self::source::{GitSource, canonicalize_url};
mod utils;
mod source;

View file

@ -96,7 +96,7 @@ fn strip_trailing_slash<'a>(path: &'a str) -> &'a str {
}
// Some hacks and heuristics for making equivalent URLs hash the same
fn canonicalize_url(url: &str) -> String {
pub fn canonicalize_url(url: &str) -> String {
let url = strip_trailing_slash(url);
// HACKHACK: For github URL's specifically just lowercase
@ -107,7 +107,12 @@ fn canonicalize_url(url: &str) -> String {
let lower_url = url.chars().map(|c|c.to_lowercase()).collect::<String>();
let url = if lower_url.as_slice().contains("github.com") {
lower_url
if lower_url.as_slice().starts_with("https") {
lower_url
} else {
let pos = lower_url.as_slice().find_str("://").unwrap_or(0);
"https".to_string() + lower_url.as_slice().slice_from(pos)
}
} else {
url.to_string()
};
@ -214,6 +219,13 @@ mod test {
assert_eq!(ident1, ident2);
}
#[test]
fn test_canonicalize_idents_different_protocls() {
let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
let ident2 = ident(&Remote(url("git://github.com/PistonDevelopers/piston")));
assert_eq!(ident1, ident2);
}
fn url(s: &str) -> Url {
url::from_str(s).unwrap()
}