Skip to content

Commit d64528f

Browse files
committed
Allow features with '/' in the name
These are just reexported features. Closes rust-lang/cargo#963
1 parent 860be95 commit d64528f

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

src/krate.rs

+14
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,20 @@ impl Crate {
211211
name.chars().all(|c| c.is_ascii())
212212
}
213213

214+
pub fn valid_feature_name(name: &str) -> bool {
215+
let mut parts = name.split('/');
216+
match parts.next() {
217+
Some(part) if !Crate::valid_name(part) => return false,
218+
None => return false,
219+
_ => {}
220+
}
221+
match parts.next() {
222+
Some(part) if !Crate::valid_name(part) => return false,
223+
_ => {}
224+
}
225+
parts.next().is_none()
226+
}
227+
214228
pub fn encodable(self, versions: Option<Vec<i32>>) -> EncodableCrate {
215229
let Crate {
216230
name, created_at, updated_at, downloads, max_version, description,

src/tests/krate.rs

+9
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,15 @@ fn new_crate_owner() {
326326
::json::<GoodCrate>(&mut response);
327327
}
328328

329+
#[test]
330+
fn valid_feature_names() {
331+
assert!(Crate::valid_feature_name("foo"));
332+
assert!(!Crate::valid_feature_name(""));
333+
assert!(!Crate::valid_feature_name("/"));
334+
assert!(!Crate::valid_feature_name("%/%"));
335+
assert!(Crate::valid_feature_name("a/a"));
336+
}
337+
329338
#[test]
330339
fn new_krate_too_big() {
331340
let (_b, app, middle) = ::app();

src/upload.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ pub struct CrateVersion(pub semver::Version);
2929
pub struct CrateVersionReq(pub semver::VersionReq);
3030
pub struct KeywordList(pub Vec<Keyword>);
3131
pub struct Keyword(pub String);
32+
pub struct Feature(pub String);
3233

3334
#[deriving(Decodable, Encodable)]
3435
pub struct CrateDependency {
3536
pub optional: bool,
3637
pub default_features: bool,
3738
pub name: CrateName,
38-
pub features: Vec<CrateName>,
39+
pub features: Vec<Feature>,
3940
pub version_req: CrateVersionReq,
4041
pub target: Option<String>,
4142
pub kind: Option<DependencyKind>,
@@ -63,6 +64,17 @@ impl<E, D: Decoder<E>> Decodable<D, E> for Keyword {
6364
}
6465
}
6566

67+
impl<E, D: Decoder<E>> Decodable<D, E> for Feature {
68+
fn decode(d: &mut D) -> Result<Feature, E> {
69+
let s = raw_try!(d.read_str());
70+
if !Crate::valid_feature_name(s.as_slice()) {
71+
return Err(d.error(format!("invalid feature name specified: {}",
72+
s).as_slice()))
73+
}
74+
Ok(Feature(s))
75+
}
76+
}
77+
6678
impl<E, D: Decoder<E>> Decodable<D, E> for CrateVersion {
6779
fn decode(d: &mut D) -> Result<CrateVersion, E> {
6880
let s = raw_try!(d.read_str());
@@ -126,6 +138,12 @@ impl<E, D: Encoder<E>> Encodable<D, E> for Keyword {
126138
}
127139
}
128140

141+
impl<E, D: Encoder<E>> Encodable<D, E> for Feature {
142+
fn encode(&self, d: &mut D) -> Result<(), E> {
143+
d.emit_str(self.as_slice())
144+
}
145+
}
146+
129147
impl<E, D: Encoder<E>> Encodable<D, E> for CrateVersion {
130148
fn encode(&self, d: &mut D) -> Result<(), E> {
131149
d.emit_str((**self).to_string().as_slice())
@@ -169,6 +187,13 @@ impl Deref<str> for Keyword {
169187
}
170188
}
171189

190+
impl Deref<str> for Feature {
191+
fn deref<'a>(&'a self) -> &'a str {
192+
let Feature(ref s) = *self;
193+
s.as_slice()
194+
}
195+
}
196+
172197
impl Deref<semver::Version> for CrateVersion {
173198
fn deref<'a>(&'a self) -> &'a semver::Version {
174199
let CrateVersion(ref s) = *self; s

0 commit comments

Comments
 (0)