Skip to content

Commit 66e049e

Browse files
committed
Change pkgid parser to allow overriding the inferred crate name.
Previously the a pkgid of `foo/rust-bar#1.0` implied a crate name of `rust-bar` and didn't allow this to be overridden. Now you can override the inferred crate name with `foo/rust-bar#bar:1.0`.
1 parent 000cda6 commit 66e049e

File tree

1 file changed

+77
-51
lines changed

1 file changed

+77
-51
lines changed

src/libsyntax/pkgid.rs

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,21 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

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

@@ -21,62 +32,55 @@ impl ToStr for PkgId {
2132
None => "0.0",
2233
Some(ref version) => version.as_slice(),
2334
};
24-
if self.path.is_empty() {
25-
format!("{}\\#{}", self.name, version)
35+
if self.path == self.name || self.path.ends_with(format!("/{}", self.name)) {
36+
format!("{}\\#{}", self.path, version)
2637
} else {
27-
format!("{}/{}\\#{}", self.path, self.name, version)
38+
format!("{}\\#{}:{}", self.path, self.name, version)
2839
}
2940
}
3041
}
3142

3243
impl FromStr for PkgId {
3344
fn from_str(s: &str) -> Option<PkgId> {
34-
let hash_idx = match s.find('#') {
35-
None => s.len(),
36-
Some(idx) => idx,
37-
};
38-
let prefix = s.slice_to(hash_idx);
39-
let name_idx = match prefix.rfind('/') {
40-
None => 0,
41-
Some(idx) => idx + 1,
42-
};
43-
if name_idx >= prefix.len() {
44-
return None;
45-
}
46-
let name = prefix.slice_from(name_idx);
47-
if name.len() <= 0 {
48-
return None;
49-
}
45+
let pieces: ~[&str] = s.splitn('#', 1).collect();
46+
let path = pieces[0].to_owned();
5047

51-
let path = if name_idx == 0 {
52-
""
53-
} else {
54-
prefix.slice_to(name_idx - 1)
55-
};
56-
let check_path = Path::new(path);
57-
if !check_path.is_relative() {
48+
if path.starts_with("/") || path.ends_with("/") ||
49+
path.starts_with(".") || path.is_empty() {
5850
return None;
5951
}
6052

61-
let version = match s.find('#') {
62-
None => None,
63-
Some(idx) => {
64-
if idx >= s.len() {
65-
None
66-
} else {
67-
let v = s.slice_from(idx + 1);
68-
if v.is_empty() {
69-
None
70-
} else {
71-
Some(v.to_owned())
72-
}
73-
}
74-
}
53+
let path_pieces: ~[&str] = path.rsplitn('/', 1).collect();
54+
let inferred_name = path_pieces[0];
55+
56+
let (name, version) = if pieces.len() == 1 {
57+
(inferred_name.to_owned(), None)
58+
} else {
59+
let hash_pieces: ~[&str] = pieces[1].splitn(':', 1).collect();
60+
let (hash_name, hash_version) = if hash_pieces.len() == 1 {
61+
("", hash_pieces[0])
62+
} else {
63+
(hash_pieces[0], hash_pieces[1])
64+
};
65+
66+
let name = if !hash_name.is_empty() {
67+
hash_name.to_owned()
68+
} else {
69+
inferred_name.to_owned()
70+
};
71+
72+
let version = if !hash_version.is_empty() {
73+
Some(hash_version.to_owned())
74+
} else {
75+
None
76+
};
77+
78+
(name, version)
7579
};
7680

77-
Some(PkgId{
78-
path: path.to_owned(),
79-
name: name.to_owned(),
81+
Some(PkgId {
82+
path: path,
83+
name: name,
8084
version: version,
8185
})
8286
}
@@ -96,15 +100,15 @@ fn bare_name() {
96100
let pkgid: PkgId = from_str("foo").expect("valid pkgid");
97101
assert_eq!(pkgid.name, ~"foo");
98102
assert_eq!(pkgid.version, None);
99-
assert_eq!(pkgid.path, ~"");
103+
assert_eq!(pkgid.path, ~"foo");
100104
}
101105
102106
#[test]
103107
fn bare_name_single_char() {
104108
let pkgid: PkgId = from_str("f").expect("valid pkgid");
105109
assert_eq!(pkgid.name, ~"f");
106110
assert_eq!(pkgid.version, None);
107-
assert_eq!(pkgid.path, ~"");
111+
assert_eq!(pkgid.path, ~"f");
108112
}
109113
110114
#[test]
@@ -118,15 +122,15 @@ fn simple_path() {
118122
let pkgid: PkgId = from_str("example.com/foo/bar").expect("valid pkgid");
119123
assert_eq!(pkgid.name, ~"bar");
120124
assert_eq!(pkgid.version, None);
121-
assert_eq!(pkgid.path, ~"example.com/foo");
125+
assert_eq!(pkgid.path, ~"example.com/foo/bar");
122126
}
123127
124128
#[test]
125129
fn simple_version() {
126130
let pkgid: PkgId = from_str("foo#1.0").expect("valid pkgid");
127131
assert_eq!(pkgid.name, ~"foo");
128132
assert_eq!(pkgid.version, Some(~"1.0"));
129-
assert_eq!(pkgid.path, ~"");
133+
assert_eq!(pkgid.path, ~"foo");
130134
}
131135
132136
#[test]
@@ -135,26 +139,48 @@ fn absolute_path() {
135139
assert!(pkgid.is_none());
136140
}
137141
142+
#[test]
143+
fn path_ends_with_slash() {
144+
let pkgid: Option<PkgId> = from_str("foo/bar/");
145+
assert!(pkgid.is_none());
146+
}
147+
138148
#[test]
139149
fn path_and_version() {
140150
let pkgid: PkgId = from_str("example.com/foo/bar#1.0").expect("valid pkgid");
141151
assert_eq!(pkgid.name, ~"bar");
142152
assert_eq!(pkgid.version, Some(~"1.0"));
143-
assert_eq!(pkgid.path, ~"example.com/foo");
153+
assert_eq!(pkgid.path, ~"example.com/foo/bar");
144154
}
145155
146156
#[test]
147157
fn single_chars() {
148158
let pkgid: PkgId = from_str("a/b#1").expect("valid pkgid");
149159
assert_eq!(pkgid.name, ~"b");
150160
assert_eq!(pkgid.version, Some(~"1"));
151-
assert_eq!(pkgid.path, ~"a");
161+
assert_eq!(pkgid.path, ~"a/b");
152162
}
153163
154164
#[test]
155165
fn missing_version() {
156166
let pkgid: PkgId = from_str("foo#").expect("valid pkgid");
157167
assert_eq!(pkgid.name, ~"foo");
158168
assert_eq!(pkgid.version, None);
159-
assert_eq!(pkgid.path, ~"");
160-
}
169+
assert_eq!(pkgid.path, ~"foo");
170+
}
171+
172+
#[test]
173+
fn path_and_name() {
174+
let pkgid: PkgId = from_str("foo/rust-bar#bar:1.0").expect("valid pkgid");
175+
assert_eq!(pkgid.name, ~"bar");
176+
assert_eq!(pkgid.version, Some(~"1.0"));
177+
assert_eq!(pkgid.path, ~"foo/rust-bar");
178+
}
179+
180+
#[test]
181+
fn empty_name() {
182+
let pkgid: PkgId = from_str("foo/bar#:1.0").expect("valid pkgid");
183+
assert_eq!(pkgid.name, ~"bar");
184+
assert_eq!(pkgid.version, Some(~"1.0"));
185+
assert_eq!(pkgid.path, ~"foo/bar");
186+
}

0 commit comments

Comments
 (0)