Skip to content

Commit d5798b3

Browse files
committed
auto merge of #10972 : metajack/rust/pkgid-with-name, r=alexcrichton
This change extends the pkgid attribute to allow of explicit crate names, instead of always inferring them based on the path. This means that if your GitHub repo is called `rust-foo`, you can have your pkgid set your library name to `foo`. You'd do this with a pkgid attribute like `github.com/somewhere/rust-foo#foo:1.0`. This is half of the fix for #10922.
2 parents 1a26bd1 + 262cc4a commit d5798b3

File tree

2 files changed

+78
-52
lines changed

2 files changed

+78
-52
lines changed

doc/rust.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ extern mod extra; // equivalent to: extern mod extra = "extra";
790790
791791
extern mod rustextra = "extra"; // linking to 'extra' under another name
792792
793-
extern mod foo = "some/where/foo#1.0"; // a full package ID for rustpkg
793+
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for rustpkg
794794
~~~~
795795

796796
##### Use declarations

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)