1
1
use crate :: core:: compiler:: { CompileKind , CompileTarget , TargetInfo } ;
2
2
use crate :: core:: resolver:: { Resolve , ResolveOpts } ;
3
- use crate :: core:: { Dependency , Package , PackageId , Workspace } ;
3
+ use crate :: core:: { Package , PackageId , Workspace } ;
4
4
use crate :: ops:: { self , Packages } ;
5
5
use crate :: util:: CargoResult ;
6
- use cargo_platform:: Cfg ;
7
- use serde:: ser;
6
+
8
7
use serde:: Serialize ;
9
8
use std:: collections:: HashMap ;
10
9
use std:: path:: PathBuf ;
@@ -35,53 +34,14 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
35
34
let packages = ws. members ( ) . cloned ( ) . collect ( ) ;
36
35
( packages, None )
37
36
} else {
38
- let specs = Packages :: All . to_package_id_specs ( ws) ?;
39
- let opts = ResolveOpts :: new (
37
+ let resolve_opts = ResolveOpts :: new (
40
38
/*dev_deps*/ true ,
41
39
& opt. features ,
42
40
opt. all_features ,
43
41
!opt. no_default_features ,
44
42
) ;
45
- let ws_resolve = ops:: resolve_ws_with_opts ( ws, opts, & specs) ?;
46
- let mut package_map = HashMap :: new ( ) ;
47
- for pkg in ws_resolve
48
- . pkg_set
49
- . get_many ( ws_resolve. pkg_set . package_ids ( ) ) ?
50
- {
51
- package_map. insert ( pkg. package_id ( ) , pkg. clone ( ) ) ;
52
- }
53
- let packages = package_map. values ( ) . map ( |p| ( * p) . clone ( ) ) . collect ( ) ;
54
- let rustc = ws. config ( ) . load_global_rustc ( Some ( ws) ) ?;
55
- let ( target, cfg) = match & opt. filter_platform {
56
- Some ( platform) => {
57
- if platform == "host" {
58
- let ti =
59
- TargetInfo :: new ( ws. config ( ) , CompileKind :: Host , & rustc, CompileKind :: Host ) ?;
60
- (
61
- Some ( rustc. host . as_str ( ) . to_string ( ) ) ,
62
- Some ( ti. cfg ( ) . iter ( ) . cloned ( ) . collect ( ) ) ,
63
- )
64
- } else {
65
- let kind = CompileKind :: Target ( CompileTarget :: new ( platform) ?) ;
66
- let ti = TargetInfo :: new ( ws. config ( ) , kind, & rustc, kind) ?;
67
- (
68
- Some ( platform. clone ( ) ) ,
69
- Some ( ti. cfg ( ) . iter ( ) . cloned ( ) . collect ( ) ) ,
70
- )
71
- }
72
- }
73
- None => ( None , None ) ,
74
- } ;
75
- let resolve = Some ( MetadataResolve {
76
- helper : ResolveHelper {
77
- packages : package_map,
78
- resolve : ws_resolve. targeted_resolve ,
79
- target,
80
- cfg,
81
- } ,
82
- root : ws. current_opt ( ) . map ( |pkg| pkg. package_id ( ) ) ,
83
- } ) ;
84
- ( packages, resolve)
43
+ let ( packages, resolve) = build_resolve_graph ( ws, resolve_opts, & opt. filter_platform ) ?;
44
+ ( packages, Some ( resolve) )
85
45
} ;
86
46
87
47
Ok ( ExportInfo {
@@ -104,81 +64,123 @@ pub struct ExportInfo {
104
64
workspace_root : PathBuf ,
105
65
}
106
66
107
- /// Newtype wrapper to provide a custom `Serialize` implementation.
108
- /// The one from lock file does not fit because it uses a non-standard
109
- /// format for `PackageId`s
110
67
#[ derive( Serialize ) ]
111
68
struct MetadataResolve {
112
- #[ serde( rename = "nodes" , serialize_with = "serialize_resolve" ) ]
113
- helper : ResolveHelper ,
69
+ nodes : Vec < MetadataResolveNode > ,
114
70
root : Option < PackageId > ,
115
71
}
116
72
117
- struct ResolveHelper {
118
- packages : HashMap < PackageId , Package > ,
119
- resolve : Resolve ,
120
- target : Option < String > ,
121
- cfg : Option < Vec < Cfg > > ,
73
+ #[ derive( Serialize ) ]
74
+ struct MetadataResolveNode {
75
+ id : PackageId ,
76
+ dependencies : Vec < PackageId > ,
77
+ deps : Vec < Dep > ,
78
+ features : Vec < String > ,
122
79
}
123
80
124
- fn serialize_resolve < S > ( helper : & ResolveHelper , s : S ) -> Result < S :: Ok , S :: Error >
125
- where
126
- S : ser:: Serializer ,
127
- {
128
- let ResolveHelper {
129
- packages,
130
- resolve,
131
- target,
132
- cfg,
133
- } = helper;
81
+ #[ derive( Serialize ) ]
82
+ struct Dep {
83
+ name : String ,
84
+ pkg : PackageId ,
85
+ }
134
86
135
- #[ derive( Serialize ) ]
136
- struct Dep {
137
- name : String ,
138
- pkg : PackageId ,
87
+ fn build_resolve_graph (
88
+ ws : & Workspace < ' _ > ,
89
+ resolve_opts : ResolveOpts ,
90
+ target : & Option < String > ,
91
+ ) -> CargoResult < ( Vec < Package > , MetadataResolve ) > {
92
+ let target_info = match target {
93
+ Some ( target) => {
94
+ let config = ws. config ( ) ;
95
+ let ct = CompileTarget :: new ( target) ?;
96
+ let short_name = ct. short_name ( ) . to_string ( ) ;
97
+ let kind = CompileKind :: Target ( ct) ;
98
+ let rustc = config. load_global_rustc ( Some ( ws) ) ?;
99
+ Some ( ( short_name, TargetInfo :: new ( config, kind, & rustc, kind) ?) )
100
+ }
101
+ None => None ,
102
+ } ;
103
+ // Resolve entire workspace.
104
+ let specs = Packages :: All . to_package_id_specs ( ws) ?;
105
+ let ws_resolve = ops:: resolve_ws_with_opts ( ws, resolve_opts, & specs) ?;
106
+ // Download all Packages. This is needed to serialize the information
107
+ // for every package. In theory this could honor target filtering,
108
+ // but that would be somewhat complex.
109
+ let mut package_map: HashMap < PackageId , Package > = ws_resolve
110
+ . pkg_set
111
+ . get_many ( ws_resolve. pkg_set . package_ids ( ) ) ?
112
+ . into_iter ( )
113
+ . map ( |pkg| ( pkg. package_id ( ) , pkg. clone ( ) ) )
114
+ . collect ( ) ;
115
+ // Start from the workspace roots, and recurse through filling out the
116
+ // map, filtering targets as necessary.
117
+ let mut node_map = HashMap :: new ( ) ;
118
+ for member_pkg in ws. members ( ) {
119
+ build_resolve_graph_r (
120
+ & mut node_map,
121
+ member_pkg. package_id ( ) ,
122
+ & ws_resolve. targeted_resolve ,
123
+ & package_map,
124
+ target_info. as_ref ( ) ,
125
+ ) ;
139
126
}
127
+ // Get a Vec of Packages.
128
+ let actual_packages = package_map
129
+ . drain ( )
130
+ . filter_map ( |( pkg_id, pkg) | node_map. get ( & pkg_id) . map ( |_| pkg) )
131
+ . collect ( ) ;
132
+ let mr = MetadataResolve {
133
+ nodes : node_map. drain ( ) . map ( |( _pkg_id, node) | node) . collect ( ) ,
134
+ root : ws. current_opt ( ) . map ( |pkg| pkg. package_id ( ) ) ,
135
+ } ;
136
+ Ok ( ( actual_packages, mr) )
137
+ }
140
138
141
- #[ derive( Serialize ) ]
142
- struct Node < ' a > {
143
- id : PackageId ,
144
- dependencies : Vec < PackageId > ,
145
- deps : Vec < Dep > ,
146
- features : Vec < & ' a str > ,
139
+ fn build_resolve_graph_r (
140
+ node_map : & mut HashMap < PackageId , MetadataResolveNode > ,
141
+ pkg_id : PackageId ,
142
+ resolve : & Resolve ,
143
+ package_map : & HashMap < PackageId , Package > ,
144
+ target : Option < & ( String , TargetInfo ) > ,
145
+ ) {
146
+ if node_map. contains_key ( & pkg_id) {
147
+ return ;
147
148
}
148
-
149
- // A filter for removing platform dependencies.
150
- let dep_filter = |( _pkg, deps) : & ( PackageId , & [ Dependency ] ) | match ( target, cfg) {
151
- ( Some ( target) , Some ( cfg) ) => deps. iter ( ) . any ( |dep| {
152
- let platform = match dep. platform ( ) {
153
- Some ( p) => p,
154
- None => return true ,
155
- } ;
156
- platform. matches ( target, cfg)
157
- } ) ,
158
- ( None , None ) => true ,
159
- _ => unreachable ! ( ) ,
149
+ let features = resolve
150
+ . features_sorted ( pkg_id)
151
+ . into_iter ( )
152
+ . map ( |s| s. to_string ( ) )
153
+ . collect ( ) ;
154
+ let deps: Vec < Dep > = resolve
155
+ . deps ( pkg_id)
156
+ . filter ( |( _dep_id, deps) | match target {
157
+ Some ( ( short_name, info) ) => deps. iter ( ) . any ( |dep| {
158
+ let platform = match dep. platform ( ) {
159
+ Some ( p) => p,
160
+ None => return true ,
161
+ } ;
162
+ platform. matches ( short_name, info. cfg ( ) )
163
+ } ) ,
164
+ None => true ,
165
+ } )
166
+ . filter_map ( |( dep_id, _deps) | {
167
+ package_map
168
+ . get ( & dep_id)
169
+ . and_then ( |pkg| pkg. targets ( ) . iter ( ) . find ( |t| t. is_lib ( ) ) )
170
+ . and_then ( |lib_target| resolve. extern_crate_name ( pkg_id, dep_id, lib_target) . ok ( ) )
171
+ . map ( |name| Dep { name, pkg : dep_id } )
172
+ } )
173
+ . collect ( ) ;
174
+ let dumb_deps: Vec < PackageId > = deps. iter ( ) . map ( |dep| dep. pkg ) . collect ( ) ;
175
+ let to_visit = dumb_deps. clone ( ) ;
176
+ let node = MetadataResolveNode {
177
+ id : pkg_id,
178
+ dependencies : dumb_deps,
179
+ deps,
180
+ features,
160
181
} ;
161
-
162
- s. collect_seq ( resolve. iter ( ) . map ( |id| {
163
- Node {
164
- id,
165
- dependencies : resolve
166
- . deps ( id)
167
- . filter ( dep_filter)
168
- . map ( |( pkg, _deps) | pkg)
169
- . collect ( ) ,
170
- deps : resolve
171
- . deps ( id)
172
- . filter ( dep_filter)
173
- . filter_map ( |( pkg, _deps) | {
174
- packages
175
- . get ( & pkg)
176
- . and_then ( |pkg| pkg. targets ( ) . iter ( ) . find ( |t| t. is_lib ( ) ) )
177
- . and_then ( |lib_target| resolve. extern_crate_name ( id, pkg, lib_target) . ok ( ) )
178
- . map ( |name| Dep { name, pkg } )
179
- } )
180
- . collect ( ) ,
181
- features : resolve. features_sorted ( id) ,
182
- }
183
- } ) )
182
+ node_map. insert ( pkg_id, node) ;
183
+ for dep_id in to_visit {
184
+ build_resolve_graph_r ( node_map, dep_id, resolve, package_map, target) ;
185
+ }
184
186
}
0 commit comments