8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
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`.
11
18
#[ deriving( Clone , Eq ) ]
12
19
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
13
22
path : ~str ,
23
+ /// The name of the crate.
14
24
name : ~str ,
25
+ /// The version of the crate.
15
26
version : Option < ~str > ,
16
27
}
17
28
@@ -21,62 +32,55 @@ impl ToStr for PkgId {
21
32
None => "0.0" ,
22
33
Some ( ref version) => version. as_slice ( ) ,
23
34
} ;
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)
26
37
} else {
27
- format ! ( "{}/{} \\ #{}" , self . path, self . name, version)
38
+ format ! ( "{}\\ #{}: {}" , self . path, self . name, version)
28
39
}
29
40
}
30
41
}
31
42
32
43
impl FromStr for PkgId {
33
44
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 ( ) ;
50
47
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 ( ) {
58
50
return None ;
59
51
}
60
52
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)
75
79
} ;
76
80
77
- Some ( PkgId {
78
- path : path. to_owned ( ) ,
79
- name : name. to_owned ( ) ,
81
+ Some ( PkgId {
82
+ path : path,
83
+ name : name,
80
84
version : version,
81
85
} )
82
86
}
@@ -96,15 +100,15 @@ fn bare_name() {
96
100
let pkgid: PkgId = from_str ( "foo" ) . expect ( "valid pkgid" ) ;
97
101
assert_eq ! ( pkgid. name, ~"foo");
98
102
assert_eq!(pkgid.version, None);
99
- assert_eq!(pkgid.path, ~" ");
103
+ assert_eq!(pkgid.path, ~" foo ");
100
104
}
101
105
102
106
#[test]
103
107
fn bare_name_single_char() {
104
108
let pkgid: PkgId = from_str(" f").expect(" valid pkgid");
105
109
assert_eq!(pkgid.name, ~" f");
106
110
assert_eq!(pkgid.version, None);
107
- assert_eq!(pkgid.path, ~" ");
111
+ assert_eq!(pkgid.path, ~" f ");
108
112
}
109
113
110
114
#[test]
@@ -118,15 +122,15 @@ fn simple_path() {
118
122
let pkgid: PkgId = from_str(" example. com/foo/bar").expect(" valid pkgid");
119
123
assert_eq!(pkgid.name, ~" bar");
120
124
assert_eq!(pkgid.version, None);
121
- assert_eq!(pkgid.path, ~" example. com/foo");
125
+ assert_eq!(pkgid.path, ~" example. com/foo/bar ");
122
126
}
123
127
124
128
#[test]
125
129
fn simple_version() {
126
130
let pkgid: PkgId = from_str(" foo#1.0 ").expect(" valid pkgid");
127
131
assert_eq!(pkgid.name, ~" foo");
128
132
assert_eq!(pkgid.version, Some(~" 1.0 "));
129
- assert_eq!(pkgid.path, ~" ");
133
+ assert_eq!(pkgid.path, ~" foo ");
130
134
}
131
135
132
136
#[test]
@@ -135,26 +139,48 @@ fn absolute_path() {
135
139
assert!(pkgid.is_none());
136
140
}
137
141
142
+ #[test]
143
+ fn path_ends_with_slash() {
144
+ let pkgid: Option<PkgId> = from_str(" foo/bar/");
145
+ assert!(pkgid.is_none());
146
+ }
147
+
138
148
#[test]
139
149
fn path_and_version() {
140
150
let pkgid: PkgId = from_str(" example. com/foo/bar#1.0 ").expect(" valid pkgid");
141
151
assert_eq!(pkgid.name, ~" bar");
142
152
assert_eq!(pkgid.version, Some(~" 1.0 "));
143
- assert_eq!(pkgid.path, ~" example. com/foo");
153
+ assert_eq!(pkgid.path, ~" example. com/foo/bar ");
144
154
}
145
155
146
156
#[test]
147
157
fn single_chars() {
148
158
let pkgid: PkgId = from_str(" a/b#1 ").expect(" valid pkgid");
149
159
assert_eq!(pkgid.name, ~" b");
150
160
assert_eq!(pkgid.version, Some(~" 1 "));
151
- assert_eq!(pkgid.path, ~" a");
161
+ assert_eq!(pkgid.path, ~" a/ b ");
152
162
}
153
163
154
164
#[test]
155
165
fn missing_version() {
156
166
let pkgid: PkgId = from_str(" foo#").expect(" valid pkgid");
157
167
assert_eq!(pkgid.name, ~" foo");
158
168
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