@@ -86,6 +86,7 @@ at your option.
86
86
*/
87
87
88
88
use std:: {
89
+ cmp:: Ordering ,
89
90
collections:: btree_map:: { self , BTreeMap } ,
90
91
env, fmt, fs, io,
91
92
path:: { Path , PathBuf } ,
@@ -94,7 +95,10 @@ use std::{
94
95
time:: SystemTime ,
95
96
} ;
96
97
97
- use toml_edit:: { DocumentMut , Item , Table , TomlError } ;
98
+ use tomling:: {
99
+ cargo:: { Dependencies , Dependency , Manifest } ,
100
+ from_str, Error as TomlError ,
101
+ } ;
98
102
99
103
/// Error type used by this crate.
100
104
pub enum Error {
@@ -125,8 +129,9 @@ impl fmt::Debug for Error {
125
129
impl fmt:: Display for Error {
126
130
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
127
131
match self {
128
- Error :: NotFound ( path) =>
129
- write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) ) ,
132
+ Error :: NotFound ( path) => {
133
+ write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) )
134
+ } ,
130
135
Error :: CargoManifestDirNotSet =>
131
136
f. write_str ( "`CARGO_MANIFEST_DIR` env variable not set." ) ,
132
137
Error :: CouldNotRead { path, .. } => write ! ( f, "Could not read `{}`." , path. display( ) ) ,
@@ -280,10 +285,12 @@ fn read_cargo_toml(
280
285
manifest_ts : SystemTime ,
281
286
workspace_manifest_ts : SystemTime ,
282
287
) -> Result < CacheEntry , Error > {
283
- let manifest = open_cargo_toml ( manifest_path) ?;
288
+ let content = open_cargo_toml ( manifest_path) ?;
289
+ let manifest = parse_cargo_toml ( & content) ?;
284
290
285
291
let workspace_dependencies = if manifest_path != workspace_manifest_path {
286
- let workspace_manifest = open_cargo_toml ( workspace_manifest_path) ?;
292
+ let content = open_cargo_toml ( workspace_manifest_path) ?;
293
+ let workspace_manifest = parse_cargo_toml ( & content) ?;
287
294
extract_workspace_dependencies ( & workspace_manifest) ?
288
295
} else {
289
296
extract_workspace_dependencies ( & manifest) ?
@@ -304,42 +311,41 @@ fn read_cargo_toml(
304
311
/// Returns a hash map that maps from dep name to the package name. Dep name
305
312
/// and package name can be the same if there doesn't exist any rename.
306
313
fn extract_workspace_dependencies (
307
- workspace_toml : & DocumentMut ,
314
+ workspace_toml : & Manifest ,
308
315
) -> Result < BTreeMap < String , String > , Error > {
309
- Ok ( workspace_dep_tables ( & workspace_toml)
316
+ Ok ( workspace_toml
317
+ . workspace ( )
318
+ . and_then ( |w| w. dependencies ( ) )
319
+ . map ( |d| d. iter ( ) )
310
320
. into_iter ( )
311
321
. flatten ( )
312
- . map ( move |( dep_name, dep_value ) | {
313
- let pkg_name = dep_value . get ( " package" ) . and_then ( |i| i . as_str ( ) ) . unwrap_or ( dep_name) ;
322
+ . map ( move |( dep_name, dep ) | {
323
+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
314
324
315
325
( dep_name. to_owned ( ) , pkg_name. to_owned ( ) )
316
326
} )
317
327
. collect ( ) )
318
328
}
319
329
320
- /// Return an iterator over all `[workspace.dependencies]`
321
- fn workspace_dep_tables ( cargo_toml : & DocumentMut ) -> Option < & Table > {
322
- cargo_toml
323
- . get ( "workspace" )
324
- . and_then ( |w| w. as_table ( ) ?. get ( "dependencies" ) ?. as_table ( ) )
325
- }
326
-
327
330
/// Make sure that the given crate name is a valid rust identifier.
328
331
fn sanitize_crate_name < S : AsRef < str > > ( name : S ) -> String {
329
332
name. as_ref ( ) . replace ( '-' , "_" )
330
333
}
331
334
335
+ /// Open the given `Cargo.toml` file and read it's content as a string.
336
+ fn open_cargo_toml ( path : & Path ) -> Result < String , Error > {
337
+ fs:: read_to_string ( path) . map_err ( |e| Error :: CouldNotRead { source : e, path : path. into ( ) } )
338
+ }
339
+
332
340
/// Open the given `Cargo.toml` and parse it into a hashmap.
333
- fn open_cargo_toml ( path : & Path ) -> Result < DocumentMut , Error > {
334
- let content = fs:: read_to_string ( path)
335
- . map_err ( |e| Error :: CouldNotRead { source : e, path : path. into ( ) } ) ?;
336
- content. parse :: < DocumentMut > ( ) . map_err ( |e| Error :: InvalidToml { source : e } )
341
+ fn parse_cargo_toml ( content : & str ) -> Result < Manifest < ' _ > , Error > {
342
+ from_str ( content) . map_err ( |e| Error :: InvalidToml { source : e } )
337
343
}
338
344
339
345
/// Extract all crate names from the given `Cargo.toml` by checking the `dependencies` and
340
346
/// `dev-dependencies`.
341
347
fn extract_crate_names (
342
- cargo_toml : & DocumentMut ,
348
+ cargo_toml : & Manifest ,
343
349
workspace_dependencies : BTreeMap < String , String > ,
344
350
) -> Result < CrateNames , Error > {
345
351
let package_name = extract_package_name ( cargo_toml) ;
@@ -355,16 +361,16 @@ fn extract_crate_names(
355
361
} ) ;
356
362
357
363
let dep_tables = dep_tables ( cargo_toml) . chain ( target_dep_tables ( cargo_toml) ) ;
358
- let dep_pkgs = dep_tables. flatten ( ) . filter_map ( move |( dep_name, dep_value ) | {
359
- let pkg_name = dep_value . get ( " package" ) . and_then ( |i| i . as_str ( ) ) . unwrap_or ( dep_name) ;
364
+ let dep_pkgs = dep_tables. filter_map ( move |( dep_name, dep ) | {
365
+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
360
366
361
367
// We already handle this via `root_pkg` above.
362
368
if package_name. as_ref ( ) . map_or ( false , |n| * n == pkg_name) {
363
- return None
369
+ return None ;
364
370
}
365
371
366
372
// Check if this is a workspace dependency.
367
- let workspace = dep_value . get ( " workspace" ) . and_then ( |w| w . as_bool ( ) ) . unwrap_or_default ( ) ;
373
+ let workspace = dep . workspace ( ) . unwrap_or_default ( ) ;
368
374
369
375
let pkg_name = workspace
370
376
. then ( || workspace_dependencies. get ( pkg_name) . map ( |p| p. as_ref ( ) ) )
@@ -379,22 +385,42 @@ fn extract_crate_names(
379
385
Ok ( root_pkg. into_iter ( ) . chain ( dep_pkgs) . collect ( ) )
380
386
}
381
387
382
- fn extract_package_name ( cargo_toml : & DocumentMut ) -> Option < & str > {
383
- cargo_toml. get ( " package" ) ? . get ( "name" ) ? . as_str ( )
388
+ fn extract_package_name < ' c > ( cargo_toml : & ' c Manifest ) -> Option < & ' c str > {
389
+ cargo_toml. package ( ) . map ( |p| p . name ( ) )
384
390
}
385
391
386
- fn target_dep_tables ( cargo_toml : & DocumentMut ) -> impl Iterator < Item = & Table > {
387
- cargo_toml. get ( "target" ) . into_iter ( ) . filter_map ( Item :: as_table) . flat_map ( |t| {
388
- t. iter ( ) . map ( |( _, value) | value) . filter_map ( Item :: as_table) . flat_map ( dep_tables)
392
+ fn target_dep_tables < ' c > (
393
+ cargo_toml : & ' c Manifest ,
394
+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
395
+ cargo_toml. targets ( ) . into_iter ( ) . flat_map ( |t| {
396
+ t. iter ( )
397
+ . map ( |( _, t) | t)
398
+ . flat_map ( |t| combined_dep_tables ( t. dependencies ( ) , t. dev_dependencies ( ) ) )
389
399
} )
390
400
}
391
401
392
- fn dep_tables ( table : & Table ) -> impl Iterator < Item = & Table > {
393
- table
394
- . get ( "dependencies" )
402
+ fn dep_tables < ' c > ( cargo_toml : & ' c Manifest ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
403
+ combined_dep_tables ( cargo_toml. dependencies ( ) , cargo_toml. dev_dependencies ( ) )
404
+ }
405
+
406
+ fn combined_dep_tables < ' c > (
407
+ deps : Option < & ' c Dependencies < ' c > > ,
408
+ dev_deps : Option < & ' c Dependencies < ' c > > ,
409
+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
410
+ let mut deps = deps
395
411
. into_iter ( )
396
- . chain ( table. get ( "dev-dependencies" ) )
397
- . filter_map ( Item :: as_table)
412
+ . flat_map ( |deps| deps. iter ( ) )
413
+ . chain ( dev_deps. into_iter ( ) . flat_map ( |deps| deps. iter ( ) ) )
414
+ . collect :: < Vec < _ > > ( ) ;
415
+ // Ensure renames (i-e deps with `package` key) are listed the last.
416
+ deps. sort_by ( |( _, a) , ( _, b) | match ( a. package ( ) , b. package ( ) ) {
417
+ ( Some ( a) , Some ( b) ) => a. cmp ( b) ,
418
+ ( Some ( _) , None ) => Ordering :: Greater ,
419
+ ( None , Some ( _) ) => Ordering :: Less ,
420
+ ( None , None ) => Ordering :: Equal ,
421
+ } ) ;
422
+
423
+ deps. into_iter ( )
398
424
}
399
425
400
426
#[ cfg( test) ]
@@ -410,16 +436,18 @@ mod tests {
410
436
) => {
411
437
#[ test]
412
438
fn $name( ) {
413
- let cargo_toml = $cargo_toml. parse :: < DocumentMut > ( )
439
+ let cargo_toml = from_str ( $cargo_toml)
414
440
. expect( "Parses `Cargo.toml`" ) ;
415
- let workspace_cargo_toml = $workspace_toml. parse :: < DocumentMut > ( )
441
+ let workspace_cargo_toml = from_str ( $workspace_toml)
416
442
. expect( "Parses workspace `Cargo.toml`" ) ;
417
443
418
444
let workspace_deps = extract_workspace_dependencies( & workspace_cargo_toml)
419
445
. expect( "Extracts workspace dependencies" ) ;
420
446
421
447
match extract_crate_names( & cargo_toml, workspace_deps)
422
- . map( |mut map| map. remove( "my_crate" ) )
448
+ . map( |mut map| {
449
+ map. remove( "my_crate" )
450
+ } )
423
451
{
424
452
$( $result ) * => ( ) ,
425
453
o => panic!( "Invalid result: {:?}" , o) ,
0 commit comments