Skip to content

Support explicit names in pkgid attributes #10972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 17, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ extern mod extra; // equivalent to: extern mod extra = "extra";

extern mod rustextra = "extra"; // linking to 'extra' under another name

extern mod foo = "some/where/foo#1.0"; // a full package ID for rustpkg
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for rustpkg
~~~~

##### Use declarations
Expand Down
128 changes: 77 additions & 51 deletions src/libsyntax/pkgid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// PkgIds identify crates and include the crate name and optionall a path and
/// version. In the full form, they look like relative URLs. Example:
/// `github.com/mozilla/rust#std:1.0` would be a package ID with a path of
/// `gitub.com/mozilla/rust` and a crate name of `std` with a version of
/// `1.0`. If no crate name is given after the hash, the name is inferred to
/// be the last component of the path. If no version is given, it is inferred
/// to be `0.0`.
#[deriving(Clone, Eq)]
pub struct PkgId {
/// A path which represents the codes origin. By convention this is the
/// URL, without `http://` or `https://` prefix, to the crate's repository
path: ~str,
/// The name of the crate.
name: ~str,
/// The version of the crate.
version: Option<~str>,
}

Expand All @@ -21,62 +32,55 @@ impl ToStr for PkgId {
None => "0.0",
Some(ref version) => version.as_slice(),
};
if self.path.is_empty() {
format!("{}\\#{}", self.name, version)
if self.path == self.name || self.path.ends_with(format!("/{}", self.name)) {
format!("{}\\#{}", self.path, version)
} else {
format!("{}/{}\\#{}", self.path, self.name, version)
format!("{}\\#{}:{}", self.path, self.name, version)
}
}
}

impl FromStr for PkgId {
fn from_str(s: &str) -> Option<PkgId> {
let hash_idx = match s.find('#') {
None => s.len(),
Some(idx) => idx,
};
let prefix = s.slice_to(hash_idx);
let name_idx = match prefix.rfind('/') {
None => 0,
Some(idx) => idx + 1,
};
if name_idx >= prefix.len() {
return None;
}
let name = prefix.slice_from(name_idx);
if name.len() <= 0 {
return None;
}
let pieces: ~[&str] = s.splitn('#', 1).collect();
let path = pieces[0].to_owned();

let path = if name_idx == 0 {
""
} else {
prefix.slice_to(name_idx - 1)
};
let check_path = Path::new(path);
if !check_path.is_relative() {
if path.starts_with("/") || path.ends_with("/") ||
path.starts_with(".") || path.is_empty() {
return None;
}

let version = match s.find('#') {
None => None,
Some(idx) => {
if idx >= s.len() {
None
} else {
let v = s.slice_from(idx + 1);
if v.is_empty() {
None
} else {
Some(v.to_owned())
}
}
}
let path_pieces: ~[&str] = path.rsplitn('/', 1).collect();
let inferred_name = path_pieces[0];

let (name, version) = if pieces.len() == 1 {
(inferred_name.to_owned(), None)
} else {
let hash_pieces: ~[&str] = pieces[1].splitn(':', 1).collect();
let (hash_name, hash_version) = if hash_pieces.len() == 1 {
("", hash_pieces[0])
} else {
(hash_pieces[0], hash_pieces[1])
};

let name = if !hash_name.is_empty() {
hash_name.to_owned()
} else {
inferred_name.to_owned()
};

let version = if !hash_version.is_empty() {
Some(hash_version.to_owned())
} else {
None
};

(name, version)
};

Some(PkgId{
path: path.to_owned(),
name: name.to_owned(),
Some(PkgId {
path: path,
name: name,
version: version,
})
}
Expand All @@ -96,15 +100,15 @@ fn bare_name() {
let pkgid: PkgId = from_str("foo").expect("valid pkgid");
assert_eq!(pkgid.name, ~"foo");
assert_eq!(pkgid.version, None);
assert_eq!(pkgid.path, ~"");
assert_eq!(pkgid.path, ~"foo");
}

#[test]
fn bare_name_single_char() {
let pkgid: PkgId = from_str("f").expect("valid pkgid");
assert_eq!(pkgid.name, ~"f");
assert_eq!(pkgid.version, None);
assert_eq!(pkgid.path, ~"");
assert_eq!(pkgid.path, ~"f");
}

#[test]
Expand All @@ -118,15 +122,15 @@ fn simple_path() {
let pkgid: PkgId = from_str("example.com/foo/bar").expect("valid pkgid");
assert_eq!(pkgid.name, ~"bar");
assert_eq!(pkgid.version, None);
assert_eq!(pkgid.path, ~"example.com/foo");
assert_eq!(pkgid.path, ~"example.com/foo/bar");
}

#[test]
fn simple_version() {
let pkgid: PkgId = from_str("foo#1.0").expect("valid pkgid");
assert_eq!(pkgid.name, ~"foo");
assert_eq!(pkgid.version, Some(~"1.0"));
assert_eq!(pkgid.path, ~"");
assert_eq!(pkgid.path, ~"foo");
}

#[test]
Expand All @@ -135,26 +139,48 @@ fn absolute_path() {
assert!(pkgid.is_none());
}

#[test]
fn path_ends_with_slash() {
let pkgid: Option<PkgId> = from_str("foo/bar/");
assert!(pkgid.is_none());
}

#[test]
fn path_and_version() {
let pkgid: PkgId = from_str("example.com/foo/bar#1.0").expect("valid pkgid");
assert_eq!(pkgid.name, ~"bar");
assert_eq!(pkgid.version, Some(~"1.0"));
assert_eq!(pkgid.path, ~"example.com/foo");
assert_eq!(pkgid.path, ~"example.com/foo/bar");
}

#[test]
fn single_chars() {
let pkgid: PkgId = from_str("a/b#1").expect("valid pkgid");
assert_eq!(pkgid.name, ~"b");
assert_eq!(pkgid.version, Some(~"1"));
assert_eq!(pkgid.path, ~"a");
assert_eq!(pkgid.path, ~"a/b");
}

#[test]
fn missing_version() {
let pkgid: PkgId = from_str("foo#").expect("valid pkgid");
assert_eq!(pkgid.name, ~"foo");
assert_eq!(pkgid.version, None);
assert_eq!(pkgid.path, ~"");
}
assert_eq!(pkgid.path, ~"foo");
}

#[test]
fn path_and_name() {
let pkgid: PkgId = from_str("foo/rust-bar#bar:1.0").expect("valid pkgid");
assert_eq!(pkgid.name, ~"bar");
assert_eq!(pkgid.version, Some(~"1.0"));
assert_eq!(pkgid.path, ~"foo/rust-bar");
}

#[test]
fn empty_name() {
let pkgid: PkgId = from_str("foo/bar#:1.0").expect("valid pkgid");
assert_eq!(pkgid.name, ~"bar");
assert_eq!(pkgid.version, Some(~"1.0"));
assert_eq!(pkgid.path, ~"foo/bar");
}