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
@@ -23,20 +23,6 @@ pub type Metadata = BTreeMap<String, String>;
23
23
impl EncodableResolve {
24
24
pub fn into_resolve ( self , ws : & Workspace ) -> CargoResult < Resolve > {
25
25
let path_deps = build_path_deps ( ws) ;
26
- let default = try!( ws. current ( ) ) . package_id ( ) . source_id ( ) ;
27
-
28
- let mut g = Graph :: new ( ) ;
29
- let mut tmp = HashMap :: new ( ) ;
30
- let mut replacements = HashMap :: new ( ) ;
31
-
32
- let id2pkgid = |id : & EncodablePackageId | {
33
- to_package_id ( & id. name , & id. version , id. source . as_ref ( ) ,
34
- default, & path_deps)
35
- } ;
36
- let dep2pkgid = |dep : & EncodableDependency | {
37
- to_package_id ( & dep. name , & dep. version , dep. source . as_ref ( ) ,
38
- default, & path_deps)
39
- } ;
40
26
41
27
let packages = {
42
28
let mut packages = self . package . unwrap_or ( Vec :: new ( ) ) ;
@@ -46,58 +32,83 @@ impl EncodableResolve {
46
32
packages
47
33
} ;
48
34
49
- let ids = try!( packages. iter ( ) . map ( & dep2pkgid)
50
- . 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
+ } ;
51
46
52
- {
53
- let mut register_pkg = |pkgid : & PackageId | {
54
- let precise = pkgid. source_id ( ) . precise ( )
55
- . map ( |s| s. to_string ( ) ) ;
56
- if tmp. insert ( pkgid. clone ( ) , precise) . is_some ( ) {
47
+ if !all_pkgs. insert ( enc_id. clone ( ) ) {
57
48
return Err ( internal ( format ! ( "package `{}` is specified twice in the lockfile" ,
58
- pkgid . name( ) ) ) ) ;
49
+ pkg . name) ) ) ;
59
50
}
60
- g. add ( pkgid. clone ( ) , & [ ] ) ;
61
- Ok ( ( ) )
62
- } ;
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
+ } ;
63
57
64
- for id in ids. iter ( ) {
65
- try!( register_pkg ( id) ) ;
58
+ assert ! ( live_pkgs. insert( enc_id, ( id, pkg) ) . is_none( ) )
66
59
}
67
- }
60
+ ( live_pkgs, all_pkgs)
61
+ } ;
68
62
69
- {
70
- let mut add_dependencies = |id : & PackageId , pkg : & EncodableDependency |
71
- -> CargoResult < ( ) > {
72
- if let Some ( ref replace) = pkg. replace {
73
- let replace = try!( id2pkgid ( replace) ) ;
74
- let replace_precise = tmp. get ( & replace) . map ( |p| {
75
- replace. with_precise ( p. clone ( ) )
76
- } ) . unwrap_or ( replace) ;
77
- replacements. insert ( id. clone ( ) , replace_precise) ;
78
- assert ! ( pkg. dependencies. is_none( ) ) ;
79
- 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) ) )
80
73
}
74
+ }
75
+ } ;
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
+ }
81
83
84
+ for & ( ref id, ref pkg) in live_pkgs. values ( ) {
82
85
let deps = match pkg. dependencies {
83
86
Some ( ref deps) => deps,
84
- None => return Ok ( ( ) ) ,
87
+ None => continue
85
88
} ;
89
+
86
90
for edge in deps. iter ( ) {
87
- let to_depend_on = try!( id2pkgid ( edge) ) ;
88
- let precise_pkgid =
89
- tmp. get ( & to_depend_on)
90
- . map ( |p| to_depend_on. with_precise ( p. clone ( ) ) )
91
- . unwrap_or ( to_depend_on. clone ( ) ) ;
92
- 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
+ }
93
94
}
94
- Ok ( ( ) )
95
- } ;
95
+ }
96
+ g
97
+ } ;
96
98
97
- for ( id, ref pkg) in ids. iter ( ) . zip ( packages) {
98
- 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
+ }
99
108
}
100
- }
109
+ replacements
110
+ } ;
111
+
101
112
let mut metadata = self . metadata . unwrap_or ( BTreeMap :: new ( ) ) ;
102
113
103
114
// Parse out all package checksums. After we do this we can be in a few
@@ -121,14 +132,14 @@ impl EncodableResolve {
121
132
for ( k, v) in metadata. iter ( ) . filter ( |p| p. 0 . starts_with ( prefix) ) {
122
133
to_remove. push ( k. to_string ( ) ) ;
123
134
let k = & k[ prefix. len ( ) ..] ;
124
- let id : EncodablePackageId = try!( k. parse ( ) . chain_error ( || {
135
+ let enc_id : EncodablePackageId = try!( k. parse ( ) . chain_error ( || {
125
136
internal ( "invalid encoding of checksum in lockfile" )
126
137
} ) ) ;
127
- let id = try! ( to_package_id ( & id . name ,
128
- & id . version ,
129
- id . source . as_ref ( ) ,
130
- default ,
131
- & path_deps ) ) ;
138
+ let id = match lookup_id ( & enc_id ) {
139
+ Ok ( Some ( id ) ) => id ,
140
+ _ => continue ,
141
+ } ;
142
+
132
143
let v = if v == "<none>" {
133
144
None
134
145
} else {
@@ -191,17 +202,6 @@ fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
191
202
}
192
203
}
193
204
194
- fn to_package_id ( name : & str ,
195
- version : & str ,
196
- source : Option < & SourceId > ,
197
- default_source : & SourceId ,
198
- path_sources : & HashMap < String , SourceId > )
199
- -> CargoResult < PackageId > {
200
- let source = source. or ( path_sources. get ( name) ) . unwrap_or ( default_source) ;
201
- PackageId :: new ( name, version, source)
202
- }
203
-
204
-
205
205
#[ derive( RustcEncodable , RustcDecodable , Debug , PartialOrd , Ord , PartialEq , Eq ) ]
206
206
pub struct EncodableDependency {
207
207
name : String ,
@@ -211,7 +211,7 @@ pub struct EncodableDependency {
211
211
replace : Option < EncodablePackageId > ,
212
212
}
213
213
214
- #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq ) ]
214
+ #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq , Hash , Clone ) ]
215
215
pub struct EncodablePackageId {
216
216
name : String ,
217
217
version : String ,
0 commit comments