@@ -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 ,
@@ -310,6 +312,7 @@ fn normalize_toml(
310
312
inherit_cell
311
313
. try_borrow_with ( || load_inheritable_fields ( gctx, manifest_file, & workspace_config) )
312
314
} ;
315
+ let workspace_root = || inherit ( ) . map ( |fields| fields. ws_root ( ) ) ;
313
316
314
317
if let Some ( original_package) = original_toml. package ( ) {
315
318
let package_name = & original_package. name ;
@@ -390,6 +393,7 @@ fn normalize_toml(
390
393
& activated_opt_deps,
391
394
None ,
392
395
& inherit,
396
+ & workspace_root,
393
397
package_root,
394
398
warnings,
395
399
) ?;
@@ -410,6 +414,7 @@ fn normalize_toml(
410
414
& activated_opt_deps,
411
415
Some ( DepKind :: Development ) ,
412
416
& inherit,
417
+ & workspace_root,
413
418
package_root,
414
419
warnings,
415
420
) ?;
@@ -430,6 +435,7 @@ fn normalize_toml(
430
435
& activated_opt_deps,
431
436
Some ( DepKind :: Build ) ,
432
437
& inherit,
438
+ & workspace_root,
433
439
package_root,
434
440
warnings,
435
441
) ?;
@@ -443,6 +449,7 @@ fn normalize_toml(
443
449
& activated_opt_deps,
444
450
None ,
445
451
& inherit,
452
+ & workspace_root,
446
453
package_root,
447
454
warnings,
448
455
) ?;
@@ -463,6 +470,7 @@ fn normalize_toml(
463
470
& activated_opt_deps,
464
471
Some ( DepKind :: Development ) ,
465
472
& inherit,
473
+ & workspace_root,
466
474
package_root,
467
475
warnings,
468
476
) ?;
@@ -483,6 +491,7 @@ fn normalize_toml(
483
491
& activated_opt_deps,
484
492
Some ( DepKind :: Build ) ,
485
493
& inherit,
494
+ & workspace_root,
486
495
package_root,
487
496
warnings,
488
497
) ?;
@@ -499,6 +508,13 @@ fn normalize_toml(
499
508
}
500
509
normalized_toml. target = ( !normalized_target. is_empty ( ) ) . then_some ( normalized_target) ;
501
510
511
+ normalized_toml. patch = normalize_patch (
512
+ gctx,
513
+ original_toml. patch . as_ref ( ) ,
514
+ & workspace_root,
515
+ features,
516
+ ) ?;
517
+
502
518
let normalized_lints = original_toml
503
519
. lints
504
520
. clone ( )
@@ -519,6 +535,37 @@ fn normalize_toml(
519
535
Ok ( normalized_toml)
520
536
}
521
537
538
+ fn normalize_patch < ' a > (
539
+ gctx : & GlobalContext ,
540
+ original_patch : Option < & BTreeMap < String , BTreeMap < PackageName , TomlDependency > > > ,
541
+ workspace_root : & dyn Fn ( ) -> CargoResult < & ' a PathBuf > ,
542
+ features : & Features ,
543
+ ) -> CargoResult < Option < BTreeMap < String , BTreeMap < PackageName , TomlDependency > > > > {
544
+ if let Some ( patch) = original_patch {
545
+ let mut normalized_patch = BTreeMap :: new ( ) ;
546
+ for ( name, packages) in patch {
547
+ let mut normalized_packages = BTreeMap :: new ( ) ;
548
+ for ( pkg, dep) in packages {
549
+ let dep = if let TomlDependency :: Detailed ( dep) = dep {
550
+ let mut dep = dep. clone ( ) ;
551
+ normalize_path_dependency ( gctx, & mut dep, workspace_root, features)
552
+ . with_context ( || {
553
+ format ! ( "resolving path for patch of ({pkg}) for source ({name})" )
554
+ } ) ?;
555
+ TomlDependency :: Detailed ( dep)
556
+ } else {
557
+ dep. clone ( )
558
+ } ;
559
+ normalized_packages. insert ( pkg. clone ( ) , dep) ;
560
+ }
561
+ normalized_patch. insert ( name. clone ( ) , normalized_packages) ;
562
+ }
563
+ Ok ( Some ( normalized_patch) )
564
+ } else {
565
+ Ok ( None )
566
+ }
567
+ }
568
+
522
569
#[ tracing:: instrument( skip_all) ]
523
570
fn normalize_package_toml < ' a > (
524
571
original_package : & manifest:: TomlPackage ,
@@ -710,6 +757,7 @@ fn normalize_dependencies<'a>(
710
757
activated_opt_deps : & HashSet < & str > ,
711
758
kind : Option < DepKind > ,
712
759
inherit : & dyn Fn ( ) -> CargoResult < & ' a InheritableFields > ,
760
+ workspace_root : & dyn Fn ( ) -> CargoResult < & ' a PathBuf > ,
713
761
package_root : & Path ,
714
762
warnings : & mut Vec < String > ,
715
763
) -> CargoResult < Option < BTreeMap < manifest:: PackageName , manifest:: InheritableDependency > > > {
@@ -768,6 +816,8 @@ fn normalize_dependencies<'a>(
768
816
}
769
817
}
770
818
}
819
+ normalize_path_dependency ( gctx, d, workspace_root, features)
820
+ . with_context ( || format ! ( "resolving path dependency {name_in_toml}" ) ) ?;
771
821
}
772
822
773
823
// if the dependency is not optional, it is always used
@@ -786,6 +836,23 @@ fn normalize_dependencies<'a>(
786
836
Ok ( Some ( deps) )
787
837
}
788
838
839
+ fn normalize_path_dependency < ' a > (
840
+ gctx : & GlobalContext ,
841
+ detailed_dep : & mut TomlDetailedDependency ,
842
+ workspace_root : & dyn Fn ( ) -> CargoResult < & ' a PathBuf > ,
843
+ features : & Features ,
844
+ ) -> CargoResult < ( ) > {
845
+ if let Some ( base) = detailed_dep. base . take ( ) {
846
+ if let Some ( path) = detailed_dep. path . as_mut ( ) {
847
+ let new_path = lookup_path_base ( & base, gctx, workspace_root, features) ?. join ( & path) ;
848
+ * path = new_path. to_str ( ) . unwrap ( ) . to_string ( ) ;
849
+ } else {
850
+ bail ! ( "`base` can only be used with path dependencies" ) ;
851
+ }
852
+ }
853
+ Ok ( ( ) )
854
+ }
855
+
789
856
fn load_inheritable_fields (
790
857
gctx : & GlobalContext ,
791
858
normalized_path : & Path ,
@@ -901,13 +968,17 @@ impl InheritableFields {
901
968
} ;
902
969
let mut dep = dep. clone ( ) ;
903
970
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
- ) ?) ;
971
+ if detailed. base . is_none ( ) {
972
+ // If this is a path dependency without a base, then update the path to be relative
973
+ // to the workspace root instead.
974
+ if let Some ( rel_path) = & detailed. path {
975
+ detailed. path = Some ( resolve_relative_path (
976
+ name,
977
+ self . ws_root ( ) ,
978
+ package_root,
979
+ rel_path,
980
+ ) ?) ;
981
+ }
911
982
}
912
983
}
913
984
Ok ( dep)
@@ -2151,6 +2222,33 @@ fn to_dependency_source_id<P: ResolveToPath + Clone>(
2151
2222
}
2152
2223
}
2153
2224
2225
+ pub ( crate ) fn lookup_path_base < ' a > (
2226
+ base : & PathBaseName ,
2227
+ gctx : & GlobalContext ,
2228
+ workspace_root : & dyn Fn ( ) -> CargoResult < & ' a PathBuf > ,
2229
+ features : & Features ,
2230
+ ) -> CargoResult < PathBuf > {
2231
+ features. require ( Feature :: path_bases ( ) ) ?;
2232
+
2233
+ // HACK: The `base` string is user controlled, but building the path is safe from injection
2234
+ // attacks since the `PathBaseName` type restricts the characters that can be used to exclude `.`
2235
+ let base_key = format ! ( "path-bases.{base}" ) ;
2236
+
2237
+ // Look up the relevant base in the Config and use that as the root.
2238
+ if let Some ( path_bases) = gctx. get :: < Option < ConfigRelativePath > > ( & base_key) ? {
2239
+ Ok ( path_bases. resolve_path ( gctx) )
2240
+ } else {
2241
+ // Otherwise, check the built-in bases.
2242
+ match base. as_str ( ) {
2243
+ "workspace" => Ok ( workspace_root ( ) ?. clone ( ) ) ,
2244
+ _ => bail ! (
2245
+ "path base `{base}` is undefined. \
2246
+ You must add an entry for `{base}` in the Cargo configuration [path-bases] table."
2247
+ ) ,
2248
+ }
2249
+ }
2250
+ }
2251
+
2154
2252
pub trait ResolveToPath {
2155
2253
fn resolve ( & self , gctx : & GlobalContext ) -> PathBuf ;
2156
2254
}
@@ -2865,6 +2963,7 @@ fn prepare_toml_for_publish(
2865
2963
let mut d = d. clone ( ) ;
2866
2964
// Path dependencies become crates.io deps.
2867
2965
d. path . take ( ) ;
2966
+ d. base . take ( ) ;
2868
2967
// Same with git dependencies.
2869
2968
d. git . take ( ) ;
2870
2969
d. branch . take ( ) ;
0 commit comments