1
1
use crate :: module_writer:: ModuleWriter ;
2
2
use crate :: { Metadata21 , SDistWriter } ;
3
3
use anyhow:: { bail, Context , Result } ;
4
- use cargo_metadata:: Metadata ;
4
+ use cargo_metadata:: { Metadata , PackageId } ;
5
5
use fs_err as fs;
6
6
use std:: collections:: HashMap ;
7
7
use std:: path:: { Path , PathBuf } ;
@@ -10,6 +10,12 @@ use std::str;
10
10
11
11
const LOCAL_DEPENDENCIES_FOLDER : & str = "local_dependencies" ;
12
12
13
+ #[ derive( Debug , Clone ) ]
14
+ struct PathDependency {
15
+ id : PackageId ,
16
+ path : PathBuf ,
17
+ }
18
+
13
19
/// We need cargo to load the local dependencies from the location where we put them in the source
14
20
/// distribution. Since there is no cargo-backed way to replace dependencies
15
21
/// (see https://github.com/rust-lang/cargo/issues/9170), we do a simple
@@ -19,7 +25,7 @@ const LOCAL_DEPENDENCIES_FOLDER: &str = "local_dependencies";
19
25
/// This method is rather frail, but unfortunately I don't know a better solution.
20
26
fn rewrite_cargo_toml (
21
27
manifest_path : impl AsRef < Path > ,
22
- known_path_deps : & HashMap < String , PathBuf > ,
28
+ known_path_deps : & HashMap < String , PathDependency > ,
23
29
root_crate : bool ,
24
30
) -> Result < String > {
25
31
let text = fs:: read_to_string ( & manifest_path) . context ( format ! (
@@ -87,7 +93,7 @@ fn add_crate_to_source_distribution(
87
93
writer : & mut SDistWriter ,
88
94
manifest_path : impl AsRef < Path > ,
89
95
prefix : impl AsRef < Path > ,
90
- known_path_deps : & HashMap < String , PathBuf > ,
96
+ known_path_deps : & HashMap < String , PathDependency > ,
91
97
root_crate : bool ,
92
98
) -> Result < ( ) > {
93
99
let output = Command :: new ( "cargo" )
@@ -157,43 +163,80 @@ fn add_crate_to_source_distribution(
157
163
Ok ( ( ) )
158
164
}
159
165
160
- /// Creates aif source distribution, packing the root crate and all local dependencies
161
- ///
162
- /// The source distribution format is specified in
163
- /// [PEP 517 under "build_sdist"](https://www.python.org/dev/peps/pep-0517/#build-sdist)
164
- /// and in
165
- /// https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-format
166
- pub fn source_distribution (
167
- wheel_dir : impl AsRef < Path > ,
168
- metadata21 : & Metadata21 ,
169
- manifest_path : impl AsRef < Path > ,
166
+ /// Get path dependencies for a cargo package
167
+ fn get_path_deps (
170
168
cargo_metadata : & Metadata ,
171
- sdist_include : Option < & Vec < String > > ,
172
- ) -> Result < PathBuf > {
169
+ resolve : & cargo_metadata:: Resolve ,
170
+ pkg_id : & cargo_metadata:: PackageId ,
171
+ visited : & HashMap < String , PathDependency > ,
172
+ ) -> Result < HashMap < String , PathDependency > > {
173
173
// Parse ids in the format:
174
174
// on unix: some_path_dep 0.1.0 (path+file:///home/konsti/maturin/test-crates/some_path_dep)
175
175
// on windows: some_path_dep 0.1.0 (path+file:///C:/konsti/maturin/test-crates/some_path_dep)
176
176
// This is not a good way to identify path dependencies, but I don't know a better one
177
- let resolve = cargo_metadata
178
- . resolve
179
- . as_ref ( )
180
- . context ( "Expected to get a dependency graph from cargo" ) ?;
181
- let known_path_deps: HashMap < String , PathBuf > = resolve
177
+ let node = resolve
182
178
. nodes
183
179
. iter ( )
184
- . filter ( |node| {
185
- & node. id != resolve. root . as_ref ( ) . unwrap ( ) && node. id . repr . contains ( "path+file://" )
186
- } )
180
+ . find ( |node| & node. id == pkg_id)
181
+ . context ( "Expected to get a node of dependency graph from cargo" ) ?;
182
+ let path_deps = node
183
+ . deps
184
+ . iter ( )
185
+ . filter ( |node| node. pkg . repr . contains ( "path+file://" ) )
187
186
. filter_map ( |node| {
188
187
cargo_metadata. packages . iter ( ) . find_map ( |pkg| {
189
- if pkg. id . repr == node. id . repr {
190
- Some ( ( pkg. name . clone ( ) , PathBuf :: from ( & pkg. manifest_path ) ) )
188
+ if pkg. id . repr == node. pkg . repr && !visited. contains_key ( & pkg. name ) {
189
+ let path_dep = PathDependency {
190
+ id : pkg. id . clone ( ) ,
191
+ path : PathBuf :: from ( & pkg. manifest_path ) ,
192
+ } ;
193
+ Some ( ( pkg. name . clone ( ) , path_dep) )
191
194
} else {
192
195
None
193
196
}
194
197
} )
195
198
} )
196
199
. collect ( ) ;
200
+ Ok ( path_deps)
201
+ }
202
+
203
+ /// Finds all path dependencies of the crate
204
+ fn find_path_deps ( cargo_metadata : & Metadata ) -> Result < HashMap < String , PathDependency > > {
205
+ let resolve = cargo_metadata
206
+ . resolve
207
+ . as_ref ( )
208
+ . context ( "Expected to get a dependency graph from cargo" ) ?;
209
+ let root = resolve
210
+ . root
211
+ . clone ( )
212
+ . context ( "Expected to get a root package id of dependency graph from cargo" ) ?;
213
+ let mut known_path_deps = HashMap :: new ( ) ;
214
+ let mut stack = vec ! [ root] ;
215
+ while let Some ( pkg_id) = stack. pop ( ) {
216
+ let path_deps = get_path_deps ( cargo_metadata, resolve, & pkg_id, & known_path_deps) ?;
217
+ if path_deps. is_empty ( ) {
218
+ continue ;
219
+ }
220
+ stack. extend ( path_deps. values ( ) . map ( |dep| dep. id . clone ( ) ) ) ;
221
+ known_path_deps. extend ( path_deps) ;
222
+ }
223
+ Ok ( known_path_deps)
224
+ }
225
+
226
+ /// Creates a source distribution, packing the root crate and all local dependencies
227
+ ///
228
+ /// The source distribution format is specified in
229
+ /// [PEP 517 under "build_sdist"](https://www.python.org/dev/peps/pep-0517/#build-sdist)
230
+ /// and in
231
+ /// https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-format
232
+ pub fn source_distribution (
233
+ wheel_dir : impl AsRef < Path > ,
234
+ metadata21 : & Metadata21 ,
235
+ manifest_path : impl AsRef < Path > ,
236
+ cargo_metadata : & Metadata ,
237
+ sdist_include : Option < & Vec < String > > ,
238
+ ) -> Result < PathBuf > {
239
+ let known_path_deps = find_path_deps ( cargo_metadata) ?;
197
240
198
241
let mut writer = SDistWriter :: new ( wheel_dir, metadata21) ?;
199
242
let root_dir = PathBuf :: from ( format ! (
@@ -203,18 +246,18 @@ pub fn source_distribution(
203
246
) ) ;
204
247
205
248
// Add local path dependencies
206
- for ( name, path ) in known_path_deps. iter ( ) {
249
+ for ( name, path_dep ) in known_path_deps. iter ( ) {
207
250
add_crate_to_source_distribution (
208
251
& mut writer,
209
- & path,
252
+ & path_dep . path ,
210
253
& root_dir. join ( LOCAL_DEPENDENCIES_FOLDER ) . join ( name) ,
211
254
& known_path_deps,
212
255
false ,
213
256
)
214
257
. context ( format ! (
215
258
"Failed to add local dependency {} at {} to the source distribution" ,
216
259
name,
217
- path. display( )
260
+ path_dep . path. display( )
218
261
) ) ?;
219
262
}
220
263
0 commit comments