@@ -86,6 +86,7 @@ at your option.
8686*/
8787
8888use std:: {
89+ cmp:: Ordering ,
8990 collections:: btree_map:: { self , BTreeMap } ,
9091 env, fmt, fs, io,
9192 path:: { Path , PathBuf } ,
@@ -94,7 +95,10 @@ use std::{
9495 time:: SystemTime ,
9596} ;
9697
97- use toml_edit:: { DocumentMut , Item , Table , TomlError } ;
98+ use tomling:: {
99+ cargo:: { Dependencies , Dependency , Manifest } ,
100+ from_str, Error as TomlError ,
101+ } ;
98102
99103/// Error type used by this crate.
100104pub enum Error {
@@ -125,10 +129,12 @@ impl fmt::Debug for Error {
125129impl fmt:: Display for Error {
126130 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
127131 match self {
128- Error :: NotFound ( path) =>
129- write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) ) ,
130- Error :: CargoManifestDirNotSet =>
131- f. write_str ( "`CARGO_MANIFEST_DIR` env variable not set." ) ,
132+ Error :: NotFound ( path) => {
133+ write ! ( f, "Could not find `Cargo.toml` in manifest dir: `{}`." , path. display( ) )
134+ } ,
135+ Error :: CargoManifestDirNotSet => {
136+ f. write_str ( "`CARGO_MANIFEST_DIR` env variable not set." )
137+ } ,
132138 Error :: CouldNotRead { path, .. } => write ! ( f, "Could not read `{}`." , path. display( ) ) ,
133139 Error :: InvalidToml { .. } => f. write_str ( "Invalid toml file." ) ,
134140 Error :: CrateNotFound { crate_name, path } => write ! (
@@ -139,6 +145,7 @@ impl fmt::Display for Error {
139145 ) ,
140146 Error :: FailedGettingWorkspaceManifestPath =>
141147 f. write_str ( "Failed to get the path of the workspace manifest path." ) ,
148+ Error :: CargoEnvVariableNotSet => f. write_str ( "`CARGO` env variable not set." ) ,
142149 }
143150 }
144151}
@@ -197,8 +204,8 @@ pub fn crate_name(orig_name: &str) -> Result<FoundCrate, Error> {
197204 let workspace_manifest_ts = cargo_toml_timestamp ( & workspace_manifest_path) ?;
198205
199206 // Timestamp changed, rebuild this cache entry.
200- if manifest_ts != cache_entry. manifest_ts ||
201- workspace_manifest_ts != cache_entry. workspace_manifest_ts
207+ if manifest_ts != cache_entry. manifest_ts
208+ || workspace_manifest_ts != cache_entry. workspace_manifest_ts
202209 {
203210 * cache_entry = read_cargo_toml (
204211 & manifest_path,
@@ -280,10 +287,12 @@ fn read_cargo_toml(
280287 manifest_ts : SystemTime ,
281288 workspace_manifest_ts : SystemTime ,
282289) -> Result < CacheEntry , Error > {
283- let manifest = open_cargo_toml ( manifest_path) ?;
290+ let content = open_cargo_toml ( manifest_path) ?;
291+ let manifest = parse_cargo_toml ( & content) ?;
284292
285293 let workspace_dependencies = if manifest_path != workspace_manifest_path {
286- let workspace_manifest = open_cargo_toml ( workspace_manifest_path) ?;
294+ let content = open_cargo_toml ( workspace_manifest_path) ?;
295+ let workspace_manifest = parse_cargo_toml ( & content) ?;
287296 extract_workspace_dependencies ( & workspace_manifest) ?
288297 } else {
289298 extract_workspace_dependencies ( & manifest) ?
@@ -304,42 +313,41 @@ fn read_cargo_toml(
304313/// Returns a hash map that maps from dep name to the package name. Dep name
305314/// and package name can be the same if there doesn't exist any rename.
306315fn extract_workspace_dependencies (
307- workspace_toml : & DocumentMut ,
316+ workspace_toml : & Manifest ,
308317) -> Result < BTreeMap < String , String > , Error > {
309- Ok ( workspace_dep_tables ( & workspace_toml)
318+ Ok ( workspace_toml
319+ . workspace ( )
320+ . and_then ( |w| w. dependencies ( ) )
321+ . map ( |d| d. iter ( ) )
310322 . into_iter ( )
311323 . 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) ;
324+ . map ( move |( dep_name, dep ) | {
325+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
314326
315327 ( dep_name. to_owned ( ) , pkg_name. to_owned ( ) )
316328 } )
317329 . collect ( ) )
318330}
319331
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-
327332/// Make sure that the given crate name is a valid rust identifier.
328333fn sanitize_crate_name < S : AsRef < str > > ( name : S ) -> String {
329334 name. as_ref ( ) . replace ( '-' , "_" )
330335}
331336
337+ /// Open the given `Cargo.toml` file and read it's content as a string.
338+ fn open_cargo_toml ( path : & Path ) -> Result < String , Error > {
339+ fs:: read_to_string ( path) . map_err ( |e| Error :: CouldNotRead { source : e, path : path. into ( ) } )
340+ }
341+
332342/// 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 } )
343+ fn parse_cargo_toml ( content : & str ) -> Result < Manifest < ' _ > , Error > {
344+ from_str ( content) . map_err ( |e| Error :: InvalidToml { source : e } )
337345}
338346
339347/// Extract all crate names from the given `Cargo.toml` by checking the `dependencies` and
340348/// `dev-dependencies`.
341349fn extract_crate_names (
342- cargo_toml : & DocumentMut ,
350+ cargo_toml : & Manifest ,
343351 workspace_dependencies : BTreeMap < String , String > ,
344352) -> Result < CrateNames , Error > {
345353 let package_name = extract_package_name ( cargo_toml) ;
@@ -355,16 +363,16 @@ fn extract_crate_names(
355363 } ) ;
356364
357365 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) ;
366+ let dep_pkgs = dep_tables. filter_map ( move |( dep_name, dep ) | {
367+ let pkg_name = dep . package ( ) . unwrap_or ( dep_name) ;
360368
361369 // We already handle this via `root_pkg` above.
362370 if package_name. as_ref ( ) . map_or ( false , |n| * n == pkg_name) {
363- return None
371+ return None ;
364372 }
365373
366374 // Check if this is a workspace dependency.
367- let workspace = dep_value . get ( " workspace" ) . and_then ( |w| w . as_bool ( ) ) . unwrap_or_default ( ) ;
375+ let workspace = dep . workspace ( ) . unwrap_or_default ( ) ;
368376
369377 let pkg_name = workspace
370378 . then ( || workspace_dependencies. get ( pkg_name) . map ( |p| p. as_ref ( ) ) )
@@ -379,22 +387,42 @@ fn extract_crate_names(
379387 Ok ( root_pkg. into_iter ( ) . chain ( dep_pkgs) . collect ( ) )
380388}
381389
382- fn extract_package_name ( cargo_toml : & DocumentMut ) -> Option < & str > {
383- cargo_toml. get ( " package" ) ? . get ( "name" ) ? . as_str ( )
390+ fn extract_package_name < ' c > ( cargo_toml : & ' c Manifest ) -> Option < & ' c str > {
391+ cargo_toml. package ( ) . map ( |p| p . name ( ) )
384392}
385393
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)
394+ fn target_dep_tables < ' c > (
395+ cargo_toml : & ' c Manifest ,
396+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
397+ cargo_toml. targets ( ) . into_iter ( ) . flat_map ( |t| {
398+ t. iter ( )
399+ . map ( |( _, t) | t)
400+ . flat_map ( |t| combined_dep_tables ( t. dependencies ( ) , t. dev_dependencies ( ) ) )
389401 } )
390402}
391403
392- fn dep_tables ( table : & Table ) -> impl Iterator < Item = & Table > {
393- table
394- . get ( "dependencies" )
404+ fn dep_tables < ' c > ( cargo_toml : & ' c Manifest ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
405+ combined_dep_tables ( cargo_toml. dependencies ( ) , cargo_toml. dev_dependencies ( ) )
406+ }
407+
408+ fn combined_dep_tables < ' c > (
409+ deps : Option < & ' c Dependencies < ' c > > ,
410+ dev_deps : Option < & ' c Dependencies < ' c > > ,
411+ ) -> impl Iterator < Item = ( & ' c str , & ' c Dependency < ' c > ) > {
412+ let mut deps = deps
395413 . into_iter ( )
396- . chain ( table. get ( "dev-dependencies" ) )
397- . filter_map ( Item :: as_table)
414+ . flat_map ( |deps| deps. iter ( ) )
415+ . chain ( dev_deps. into_iter ( ) . flat_map ( |deps| deps. iter ( ) ) )
416+ . collect :: < Vec < _ > > ( ) ;
417+ // Ensure renames (i-e deps with `package` key) are listed the last.
418+ deps. sort_by ( |( _, a) , ( _, b) | match ( a. package ( ) , b. package ( ) ) {
419+ ( Some ( a) , Some ( b) ) => a. cmp ( b) ,
420+ ( Some ( _) , None ) => Ordering :: Greater ,
421+ ( None , Some ( _) ) => Ordering :: Less ,
422+ ( None , None ) => Ordering :: Equal ,
423+ } ) ;
424+
425+ deps. into_iter ( )
398426}
399427
400428#[ cfg( test) ]
@@ -410,16 +438,18 @@ mod tests {
410438 ) => {
411439 #[ test]
412440 fn $name( ) {
413- let cargo_toml = $cargo_toml. parse :: < DocumentMut > ( )
441+ let cargo_toml = from_str ( $cargo_toml)
414442 . expect( "Parses `Cargo.toml`" ) ;
415- let workspace_cargo_toml = $workspace_toml. parse :: < DocumentMut > ( )
443+ let workspace_cargo_toml = from_str ( $workspace_toml)
416444 . expect( "Parses workspace `Cargo.toml`" ) ;
417445
418446 let workspace_deps = extract_workspace_dependencies( & workspace_cargo_toml)
419447 . expect( "Extracts workspace dependencies" ) ;
420448
421449 match extract_crate_names( & cargo_toml, workspace_deps)
422- . map( |mut map| map. remove( "my_crate" ) )
450+ . map( |mut map| {
451+ map. remove( "my_crate" )
452+ } )
423453 {
424454 $( $result ) * => ( ) ,
425455 o => panic!( "Invalid result: {:?}" , o) ,
0 commit comments