1
- use std:: collections:: { HashMap , BTreeMap } ;
1
+ use std:: collections:: { HashMap , HashSet , BTreeMap } ;
2
2
use std:: fmt;
3
3
use std:: str:: FromStr ;
4
4
@@ -24,17 +24,6 @@ impl EncodableResolve {
24
24
pub fn into_resolve ( self , ws : & Workspace ) -> CargoResult < Resolve > {
25
25
let path_deps = build_path_deps ( ws) ;
26
26
27
- let mut g = Graph :: new ( ) ;
28
- let mut tmp = HashMap :: new ( ) ;
29
- let mut replacements = HashMap :: new ( ) ;
30
-
31
- let id2pkgid = |id : & EncodablePackageId | {
32
- to_package_id ( & id. name , & id. version , id. source . as_ref ( ) , & path_deps)
33
- } ;
34
- let dep2pkgid = |dep : & EncodableDependency | {
35
- to_package_id ( & dep. name , & dep. version , dep. source . as_ref ( ) , & path_deps)
36
- } ;
37
-
38
27
let packages = {
39
28
let mut packages = self . package . unwrap_or ( Vec :: new ( ) ) ;
40
29
if let Some ( root) = self . root {
@@ -43,58 +32,83 @@ impl EncodableResolve {
43
32
packages
44
33
} ;
45
34
46
- let ids = try!( packages. iter ( ) . map ( & dep2pkgid)
47
- . collect :: < CargoResult < Vec < _ > > > ( ) ) ;
35
+ // `PackageId`s in the lock file don't include the `source` part
36
+ // for workspace members, so we reconstruct proper ids.
37
+ let ( live_pkgs, all_pkgs) = {
38
+ let mut live_pkgs = HashMap :: new ( ) ;
39
+ let mut all_pkgs = HashSet :: new ( ) ;
40
+ for pkg in packages. iter ( ) {
41
+ let enc_id = EncodablePackageId {
42
+ name : pkg. name . clone ( ) ,
43
+ version : pkg. version . clone ( ) ,
44
+ source : pkg. source . clone ( ) ,
45
+ } ;
48
46
49
- {
50
- let mut register_pkg = |pkgid : & PackageId | {
51
- let precise = pkgid. source_id ( ) . precise ( )
52
- . map ( |s| s. to_string ( ) ) ;
53
- if tmp. insert ( pkgid. clone ( ) , precise) . is_some ( ) {
47
+ if !all_pkgs. insert ( enc_id. clone ( ) ) {
54
48
return Err ( internal ( format ! ( "package `{}` is specified twice in the lockfile" ,
55
- pkgid . name( ) ) ) ) ;
49
+ pkg . name) ) ) ;
56
50
}
57
- g. add ( pkgid. clone ( ) , & [ ] ) ;
58
- Ok ( ( ) )
59
- } ;
51
+ let id = match pkg. source . as_ref ( ) . or ( path_deps. get ( & pkg. name ) ) {
52
+ // We failed to find a local package in the workspace.
53
+ // It must have been removed and should be ignored.
54
+ None => continue ,
55
+ Some ( source) => try!( PackageId :: new ( & pkg. name , & pkg. version , source) )
56
+ } ;
60
57
61
- for id in ids. iter ( ) {
62
- try!( register_pkg ( id) ) ;
58
+ assert ! ( live_pkgs. insert( enc_id, ( id, pkg) ) . is_none( ) )
63
59
}
64
- }
60
+ ( live_pkgs, all_pkgs)
61
+ } ;
65
62
66
- {
67
- let mut add_dependencies = |id : & PackageId , pkg : & EncodableDependency |
68
- -> CargoResult < ( ) > {
69
- if let Some ( ref replace) = pkg. replace {
70
- let replace = try!( id2pkgid ( replace) ) ;
71
- let replace_precise = tmp. get ( & replace) . map ( |p| {
72
- replace. with_precise ( p. clone ( ) )
73
- } ) . unwrap_or ( replace) ;
74
- replacements. insert ( id. clone ( ) , replace_precise) ;
75
- assert ! ( pkg. dependencies. is_none( ) ) ;
76
- return Ok ( ( ) )
63
+ let lookup_id = |enc_id : & EncodablePackageId | -> CargoResult < Option < PackageId > > {
64
+ match live_pkgs. get ( enc_id) {
65
+ Some ( & ( ref id, _) ) => Ok ( Some ( id. clone ( ) ) ) ,
66
+ None => if all_pkgs. contains ( enc_id) {
67
+ // Package is found in the lockfile, but it is
68
+ // no longer a member of the workspace.
69
+ Ok ( None )
70
+ } else {
71
+ Err ( internal ( format ! ( "package `{}` is specified as a dependency, \
72
+ but is missing from the package list", enc_id) ) )
77
73
}
74
+ }
75
+ } ;
78
76
77
+ let g = {
78
+ let mut g = Graph :: new ( ) ;
79
+
80
+ for & ( ref id, _) in live_pkgs. values ( ) {
81
+ g. add ( id. clone ( ) , & [ ] ) ;
82
+ }
83
+
84
+ for & ( ref id, ref pkg) in live_pkgs. values ( ) {
79
85
let deps = match pkg. dependencies {
80
86
Some ( ref deps) => deps,
81
- None => return Ok ( ( ) ) ,
87
+ None => continue
82
88
} ;
89
+
83
90
for edge in deps. iter ( ) {
84
- let to_depend_on = try!( id2pkgid ( edge) ) ;
85
- let precise_pkgid =
86
- tmp. get ( & to_depend_on)
87
- . map ( |p| to_depend_on. with_precise ( p. clone ( ) ) )
88
- . unwrap_or ( to_depend_on. clone ( ) ) ;
89
- g. link ( id. clone ( ) , precise_pkgid) ;
91
+ if let Some ( to_depend_on) = try!( lookup_id ( edge) ) {
92
+ g. link ( id. clone ( ) , to_depend_on) ;
93
+ }
90
94
}
91
- Ok ( ( ) )
92
- } ;
95
+ }
96
+ g
97
+ } ;
93
98
94
- for ( id, ref pkg) in ids. iter ( ) . zip ( packages) {
95
- try!( add_dependencies ( id, pkg) ) ;
99
+ let replacements = {
100
+ let mut replacements = HashMap :: new ( ) ;
101
+ for & ( ref id, ref pkg) in live_pkgs. values ( ) {
102
+ if let Some ( ref replace) = pkg. replace {
103
+ assert ! ( pkg. dependencies. is_none( ) ) ;
104
+ if let Some ( replace_id) = try!( lookup_id ( replace) ) {
105
+ replacements. insert ( id. clone ( ) , replace_id) ;
106
+ }
107
+ }
96
108
}
97
- }
109
+ replacements
110
+ } ;
111
+
98
112
let mut metadata = self . metadata . unwrap_or ( BTreeMap :: new ( ) ) ;
99
113
100
114
// Parse out all package checksums. After we do this we can be in a few
@@ -118,13 +132,14 @@ impl EncodableResolve {
118
132
for ( k, v) in metadata. iter ( ) . filter ( |p| p. 0 . starts_with ( prefix) ) {
119
133
to_remove. push ( k. to_string ( ) ) ;
120
134
let k = & k[ prefix. len ( ) ..] ;
121
- let id : EncodablePackageId = try!( k. parse ( ) . chain_error ( || {
135
+ let enc_id : EncodablePackageId = try!( k. parse ( ) . chain_error ( || {
122
136
internal ( "invalid encoding of checksum in lockfile" )
123
137
} ) ) ;
124
- let id = try!( to_package_id ( & id. name ,
125
- & id. version ,
126
- id. source . as_ref ( ) ,
127
- & path_deps) ) ;
138
+ let id = match lookup_id ( & enc_id) {
139
+ Ok ( Some ( id) ) => id,
140
+ _ => continue ,
141
+ } ;
142
+
128
143
let v = if v == "<none>" {
129
144
None
130
145
} else {
@@ -187,20 +202,6 @@ fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
187
202
}
188
203
}
189
204
190
- fn to_package_id ( name : & str ,
191
- version : & str ,
192
- source : Option < & SourceId > ,
193
- path_sources : & HashMap < String , SourceId > )
194
- -> CargoResult < PackageId > {
195
- if let Some ( source) = source. or ( path_sources. get ( name) ) {
196
- PackageId :: new ( name, version, source)
197
- } else {
198
- let dummy_source = SourceId :: from_url ( "path+file:///dummy_path" ) . unwrap ( ) ;
199
- PackageId :: new ( name, version, & dummy_source)
200
- }
201
- }
202
-
203
-
204
205
#[ derive( RustcEncodable , RustcDecodable , Debug , PartialOrd , Ord , PartialEq , Eq ) ]
205
206
pub struct EncodableDependency {
206
207
name : String ,
@@ -210,7 +211,7 @@ pub struct EncodableDependency {
210
211
replace : Option < EncodablePackageId > ,
211
212
}
212
213
213
- #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq ) ]
214
+ #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq , Hash , Clone ) ]
214
215
pub struct EncodablePackageId {
215
216
name : String ,
216
217
version : String ,
0 commit comments