@@ -10,7 +10,9 @@ use crate::AlreadyPrintedError;
10
10
use anyhow:: { anyhow, bail, Context as _} ;
11
11
use cargo_platform:: Platform ;
12
12
use cargo_util:: paths:: { self , normalize_path} ;
13
- use cargo_util_schemas:: manifest:: { self , TomlManifest } ;
13
+ use cargo_util_schemas:: manifest:: {
14
+ self , PackageName , PathBaseName , TomlDependency , TomlDetailedDependency , TomlManifest ,
15
+ } ;
14
16
use cargo_util_schemas:: manifest:: { RustVersion , StringOrBool } ;
15
17
use itertools:: Itertools ;
16
18
use lazycell:: LazyCell ;
@@ -296,7 +298,7 @@ fn normalize_toml(
296
298
features : None ,
297
299
target : None ,
298
300
replace : original_toml. replace . clone ( ) ,
299
- patch : original_toml . patch . clone ( ) ,
301
+ patch : None ,
300
302
workspace : original_toml. workspace . clone ( ) ,
301
303
badges : None ,
302
304
lints : None ,
@@ -305,11 +307,18 @@ fn normalize_toml(
305
307
306
308
let package_root = manifest_file. parent ( ) . unwrap ( ) ;
307
309
308
- let inherit_cell: LazyCell < InheritableFields > = LazyCell :: new ( ) ;
309
- let inherit = || {
310
+ let inherit_cell: LazyCell < Option < InheritableFields > > = LazyCell :: new ( ) ;
311
+ let load_inherit = || {
310
312
inherit_cell
311
313
. try_borrow_with ( || load_inheritable_fields ( gctx, manifest_file, & workspace_config) )
312
314
} ;
315
+ let inherit = || {
316
+ load_inherit ( ) ?
317
+ . as_ref ( )
318
+ . ok_or_else ( || anyhow ! ( "failed to find a workspace root" ) )
319
+ } ;
320
+ let workspace_root =
321
+ || load_inherit ( ) . map ( |inherit| inherit. as_ref ( ) . map ( |fields| fields. ws_root ( ) ) ) ;
313
322
314
323
if let Some ( original_package) = original_toml. package ( ) {
315
324
let package_name = & original_package. name ;
@@ -390,6 +399,7 @@ fn normalize_toml(
390
399
& activated_opt_deps,
391
400
None ,
392
401
& inherit,
402
+ & workspace_root,
393
403
package_root,
394
404
warnings,
395
405
) ?;
@@ -410,6 +420,7 @@ fn normalize_toml(
410
420
& activated_opt_deps,
411
421
Some ( DepKind :: Development ) ,
412
422
& inherit,
423
+ & workspace_root,
413
424
package_root,
414
425
warnings,
415
426
) ?;
@@ -430,6 +441,7 @@ fn normalize_toml(
430
441
& activated_opt_deps,
431
442
Some ( DepKind :: Build ) ,
432
443
& inherit,
444
+ & workspace_root,
433
445
package_root,
434
446
warnings,
435
447
) ?;
@@ -443,6 +455,7 @@ fn normalize_toml(
443
455
& activated_opt_deps,
444
456
None ,
445
457
& inherit,
458
+ & workspace_root,
446
459
package_root,
447
460
warnings,
448
461
) ?;
@@ -463,6 +476,7 @@ fn normalize_toml(
463
476
& activated_opt_deps,
464
477
Some ( DepKind :: Development ) ,
465
478
& inherit,
479
+ & workspace_root,
466
480
package_root,
467
481
warnings,
468
482
) ?;
@@ -483,6 +497,7 @@ fn normalize_toml(
483
497
& activated_opt_deps,
484
498
Some ( DepKind :: Build ) ,
485
499
& inherit,
500
+ & workspace_root,
486
501
package_root,
487
502
warnings,
488
503
) ?;
@@ -499,6 +514,13 @@ fn normalize_toml(
499
514
}
500
515
normalized_toml. target = ( !normalized_target. is_empty ( ) ) . then_some ( normalized_target) ;
501
516
517
+ normalized_toml. patch = normalize_patch (
518
+ gctx,
519
+ original_toml. patch . as_ref ( ) ,
520
+ & workspace_root,
521
+ features,
522
+ ) ?;
523
+
502
524
let normalized_lints = original_toml
503
525
. lints
504
526
. clone ( )
@@ -519,6 +541,37 @@ fn normalize_toml(
519
541
Ok ( normalized_toml)
520
542
}
521
543
544
+ fn normalize_patch < ' a > (
545
+ gctx : & GlobalContext ,
546
+ original_patch : Option < & BTreeMap < String , BTreeMap < PackageName , TomlDependency > > > ,
547
+ workspace_root : & dyn Fn ( ) -> CargoResult < Option < & ' a PathBuf > > ,
548
+ features : & Features ,
549
+ ) -> CargoResult < Option < BTreeMap < String , BTreeMap < PackageName , TomlDependency > > > > {
550
+ if let Some ( patch) = original_patch {
551
+ let mut normalized_patch = BTreeMap :: new ( ) ;
552
+ for ( name, packages) in patch {
553
+ let mut normalized_packages = BTreeMap :: new ( ) ;
554
+ for ( pkg, dep) in packages {
555
+ let dep = if let TomlDependency :: Detailed ( dep) = dep {
556
+ let mut dep = dep. clone ( ) ;
557
+ normalize_path_dependency ( gctx, & mut dep, workspace_root, features)
558
+ . with_context ( || {
559
+ format ! ( "resolving path for patch of ({pkg}) for source ({name})" )
560
+ } ) ?;
561
+ TomlDependency :: Detailed ( dep)
562
+ } else {
563
+ dep. clone ( )
564
+ } ;
565
+ normalized_packages. insert ( pkg. clone ( ) , dep) ;
566
+ }
567
+ normalized_patch. insert ( name. clone ( ) , normalized_packages) ;
568
+ }
569
+ Ok ( Some ( normalized_patch) )
570
+ } else {
571
+ Ok ( None )
572
+ }
573
+ }
574
+
522
575
#[ tracing:: instrument( skip_all) ]
523
576
fn normalize_package_toml < ' a > (
524
577
original_package : & manifest:: TomlPackage ,
@@ -710,6 +763,7 @@ fn normalize_dependencies<'a>(
710
763
activated_opt_deps : & HashSet < & str > ,
711
764
kind : Option < DepKind > ,
712
765
inherit : & dyn Fn ( ) -> CargoResult < & ' a InheritableFields > ,
766
+ workspace_root : & dyn Fn ( ) -> CargoResult < Option < & ' a PathBuf > > ,
713
767
package_root : & Path ,
714
768
warnings : & mut Vec < String > ,
715
769
) -> CargoResult < Option < BTreeMap < manifest:: PackageName , manifest:: InheritableDependency > > > {
@@ -768,6 +822,8 @@ fn normalize_dependencies<'a>(
768
822
}
769
823
}
770
824
}
825
+ normalize_path_dependency ( gctx, d, workspace_root, features)
826
+ . with_context ( || format ! ( "resolving path dependency ({name_in_toml})" ) ) ?;
771
827
}
772
828
773
829
// if the dependency is not optional, it is always used
@@ -786,13 +842,30 @@ fn normalize_dependencies<'a>(
786
842
Ok ( Some ( deps) )
787
843
}
788
844
845
+ fn normalize_path_dependency < ' a > (
846
+ gctx : & GlobalContext ,
847
+ detailed_dep : & mut TomlDetailedDependency ,
848
+ workspace_root : & dyn Fn ( ) -> CargoResult < Option < & ' a PathBuf > > ,
849
+ features : & Features ,
850
+ ) -> CargoResult < ( ) > {
851
+ if let Some ( base) = detailed_dep. base . take ( ) {
852
+ if let Some ( path) = detailed_dep. path . as_mut ( ) {
853
+ let new_path = lookup_path_base ( & base, gctx, workspace_root, features) ?. join ( & path) ;
854
+ * path = new_path. to_str ( ) . unwrap ( ) . to_string ( ) ;
855
+ } else {
856
+ bail ! ( "`base` can only be used with path dependencies" ) ;
857
+ }
858
+ }
859
+ Ok ( ( ) )
860
+ }
861
+
789
862
fn load_inheritable_fields (
790
863
gctx : & GlobalContext ,
791
864
normalized_path : & Path ,
792
865
workspace_config : & WorkspaceConfig ,
793
- ) -> CargoResult < InheritableFields > {
866
+ ) -> CargoResult < Option < InheritableFields > > {
794
867
match workspace_config {
795
- WorkspaceConfig :: Root ( root) => Ok ( root. inheritable ( ) . clone ( ) ) ,
868
+ WorkspaceConfig :: Root ( root) => Ok ( Some ( root. inheritable ( ) . clone ( ) ) ) ,
796
869
WorkspaceConfig :: Member {
797
870
root : Some ( ref path_to_root) ,
798
871
} => {
@@ -802,14 +875,11 @@ fn load_inheritable_fields(
802
875
. join ( path_to_root)
803
876
. join ( "Cargo.toml" ) ;
804
877
let root_path = paths:: normalize_path ( & path) ;
805
- inheritable_from_path ( gctx, root_path)
806
- }
807
- WorkspaceConfig :: Member { root : None } => {
808
- match find_workspace_root ( & normalized_path, gctx) ? {
809
- Some ( path_to_root) => inheritable_from_path ( gctx, path_to_root) ,
810
- None => Err ( anyhow ! ( "failed to find a workspace root" ) ) ,
811
- }
878
+ inheritable_from_path ( gctx, root_path) . map ( Some )
812
879
}
880
+ WorkspaceConfig :: Member { root : None } => find_workspace_root ( & normalized_path, gctx) ?
881
+ . map ( |path_to_root| inheritable_from_path ( gctx, path_to_root) )
882
+ . transpose ( ) ,
813
883
}
814
884
}
815
885
@@ -901,13 +971,17 @@ impl InheritableFields {
901
971
} ;
902
972
let mut dep = dep. clone ( ) ;
903
973
if let manifest:: TomlDependency :: Detailed ( detailed) = & mut dep {
904
- if let Some ( rel_path) = & detailed. path {
905
- detailed. path = Some ( resolve_relative_path (
906
- name,
907
- self . ws_root ( ) ,
908
- package_root,
909
- rel_path,
910
- ) ?) ;
974
+ if detailed. base . is_none ( ) {
975
+ // If this is a path dependency without a base, then update the path to be relative
976
+ // to the workspace root instead.
977
+ if let Some ( rel_path) = & detailed. path {
978
+ detailed. path = Some ( resolve_relative_path (
979
+ name,
980
+ self . ws_root ( ) ,
981
+ package_root,
982
+ rel_path,
983
+ ) ?) ;
984
+ }
911
985
}
912
986
}
913
987
Ok ( dep)
@@ -2151,6 +2225,41 @@ fn to_dependency_source_id<P: ResolveToPath + Clone>(
2151
2225
}
2152
2226
}
2153
2227
2228
+ pub ( crate ) fn lookup_path_base < ' a > (
2229
+ base : & PathBaseName ,
2230
+ gctx : & GlobalContext ,
2231
+ workspace_root : & dyn Fn ( ) -> CargoResult < Option < & ' a PathBuf > > ,
2232
+ features : & Features ,
2233
+ ) -> CargoResult < PathBuf > {
2234
+ features. require ( Feature :: path_bases ( ) ) ?;
2235
+
2236
+ // Look up the relevant base in the Config and use that as the root.
2237
+ // NOTE: The `base` string is user controlled, but building the path is safe from injection
2238
+ // attacks since the `PathBaseName` type restricts the characters that can be used.
2239
+ if let Some ( path_bases) =
2240
+ gctx. get :: < Option < ConfigRelativePath > > ( & format ! ( "path-bases.{base}" ) ) ?
2241
+ {
2242
+ Ok ( path_bases. resolve_path ( gctx) )
2243
+ } else {
2244
+ // Otherwise, check the built-in bases.
2245
+ match base. as_str ( ) {
2246
+ "workspace" => {
2247
+ if let Some ( workspace_root) = workspace_root ( ) ? {
2248
+ Ok ( workspace_root. clone ( ) )
2249
+ } else {
2250
+ bail ! (
2251
+ "the `workspace` built-in path base cannot be used outside of a workspace."
2252
+ )
2253
+ }
2254
+ }
2255
+ _ => bail ! (
2256
+ "path base `{base}` is undefined. \
2257
+ You must add an entry for `{base}` in the Cargo configuration [path-bases] table."
2258
+ ) ,
2259
+ }
2260
+ }
2261
+ }
2262
+
2154
2263
pub trait ResolveToPath {
2155
2264
fn resolve ( & self , gctx : & GlobalContext ) -> PathBuf ;
2156
2265
}
@@ -2865,6 +2974,7 @@ fn prepare_toml_for_publish(
2865
2974
let mut d = d. clone ( ) ;
2866
2975
// Path dependencies become crates.io deps.
2867
2976
d. path . take ( ) ;
2977
+ d. base . take ( ) ;
2868
2978
// Same with git dependencies.
2869
2979
d. git . take ( ) ;
2870
2980
d. branch . take ( ) ;
0 commit comments