@@ -12,6 +12,7 @@ use std::str::FromStr;
1212use anyhow:: Context as _;
1313use cargo_util:: paths;
1414use cargo_util_schemas:: core:: PartialVersion ;
15+ use cargo_util_schemas:: manifest:: PathBaseName ;
1516use cargo_util_schemas:: manifest:: RustVersion ;
1617use indexmap:: IndexSet ;
1718use itertools:: Itertools ;
@@ -20,6 +21,7 @@ use toml_edit::Item as TomlItem;
2021use crate :: core:: dependency:: DepKind ;
2122use crate :: core:: registry:: PackageRegistry ;
2223use crate :: core:: FeatureValue ;
24+ use crate :: core:: Features ;
2325use crate :: core:: Package ;
2426use crate :: core:: Registry ;
2527use crate :: core:: Shell ;
@@ -28,6 +30,7 @@ use crate::core::Workspace;
2830use crate :: sources:: source:: QueryKind ;
2931use crate :: util:: cache_lock:: CacheLockMode ;
3032use crate :: util:: style;
33+ use crate :: util:: toml:: lookup_path_base;
3134use crate :: util:: toml_mut:: dependency:: Dependency ;
3235use crate :: util:: toml_mut:: dependency:: GitSource ;
3336use crate :: util:: toml_mut:: dependency:: MaybeWorkspace ;
@@ -197,7 +200,13 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
197200
198201 print_dep_table_msg ( & mut options. gctx . shell ( ) , & dep) ?;
199202
200- manifest. insert_into_table ( & dep_table, & dep) ?;
203+ manifest. insert_into_table (
204+ & dep_table,
205+ & dep,
206+ workspace. gctx ( ) ,
207+ workspace. root ( ) ,
208+ options. spec . manifest ( ) . unstable_features ( ) ,
209+ ) ?;
201210 if dep. optional == Some ( true ) {
202211 let is_namespaced_features_supported =
203212 check_rust_version_for_optional_dependency ( options. spec . rust_version ( ) ) ?;
@@ -270,8 +279,11 @@ pub struct DepOp {
270279 /// Registry for looking up dependency version
271280 pub registry : Option < String > ,
272281
273- /// Git repo for dependency
282+ /// File system path for dependency
274283 pub path : Option < String > ,
284+ /// Specify a named base for a path dependency
285+ pub base : Option < String > ,
286+
275287 /// Git repo for dependency
276288 pub git : Option < String > ,
277289 /// Specify an alternative git branch
@@ -332,7 +344,19 @@ fn resolve_dependency(
332344 selected
333345 } else if let Some ( raw_path) = & arg. path {
334346 let path = paths:: normalize_path ( & std:: env:: current_dir ( ) ?. join ( raw_path) ) ;
335- let src = PathSource :: new ( & path) ;
347+ let mut src = PathSource :: new ( path) ;
348+ src. base = arg. base . clone ( ) ;
349+
350+ if let Some ( base) = & arg. base {
351+ // Validate that the base is valid.
352+ let workspace_root = || Ok ( ws. root_manifest ( ) . parent ( ) . unwrap ( ) ) ;
353+ lookup_path_base (
354+ & PathBaseName :: new ( base. clone ( ) ) ?,
355+ & gctx,
356+ & workspace_root,
357+ spec. manifest ( ) . unstable_features ( ) ,
358+ ) ?;
359+ }
336360
337361 let selected = if let Some ( crate_spec) = & crate_spec {
338362 if let Some ( v) = crate_spec. version_req ( ) {
@@ -349,9 +373,13 @@ fn resolve_dependency(
349373 }
350374 selected
351375 } else {
352- let mut source = crate :: sources:: PathSource :: new ( & path, src. source_id ( ) ?, gctx) ;
376+ let mut source = crate :: sources:: PathSource :: new ( & src . path , src. source_id ( ) ?, gctx) ;
353377 let package = source. root_package ( ) ?;
354- Dependency :: from ( package. summary ( ) )
378+ let mut selected = Dependency :: from ( package. summary ( ) ) ;
379+ if let Some ( Source :: Path ( selected_src) ) = & mut selected. source {
380+ selected_src. base = src. base ;
381+ }
382+ selected
355383 } ;
356384 selected
357385 } else if let Some ( crate_spec) = & crate_spec {
@@ -361,9 +389,16 @@ fn resolve_dependency(
361389 } ;
362390 selected_dep = populate_dependency ( selected_dep, arg) ;
363391
364- let lookup = |dep_key : & _ | get_existing_dependency ( manifest, dep_key, section) ;
392+ let lookup = |dep_key : & _ | {
393+ get_existing_dependency (
394+ ws,
395+ spec. manifest ( ) . unstable_features ( ) ,
396+ manifest,
397+ dep_key,
398+ section,
399+ )
400+ } ;
365401 let old_dep = fuzzy_lookup ( & mut selected_dep, lookup, gctx) ?;
366-
367402 let mut dependency = if let Some ( mut old_dep) = old_dep. clone ( ) {
368403 if old_dep. name != selected_dep. name {
369404 // Assuming most existing keys are not relevant when the package changes
@@ -385,7 +420,9 @@ fn resolve_dependency(
385420 if dependency. source ( ) . is_none ( ) {
386421 // Checking for a workspace dependency happens first since a member could be specified
387422 // in the workspace dependencies table as a dependency
388- let lookup = |toml_key : & _ | Ok ( find_workspace_dep ( toml_key, ws. root_manifest ( ) ) . ok ( ) ) ;
423+ let lookup = |toml_key : & _ | {
424+ Ok ( find_workspace_dep ( toml_key, ws, ws. root_manifest ( ) , ws. unstable_features ( ) ) . ok ( ) )
425+ } ;
389426 if let Some ( _dep) = fuzzy_lookup ( & mut dependency, lookup, gctx) ? {
390427 dependency = dependency. set_source ( WorkspaceSource :: new ( ) ) ;
391428 } else if let Some ( package) = ws. members ( ) . find ( |p| p. name ( ) . as_str ( ) == dependency. name ) {
@@ -432,7 +469,12 @@ fn resolve_dependency(
432469 let query = dependency. query ( gctx) ?;
433470 let query = match query {
434471 MaybeWorkspace :: Workspace ( _workspace) => {
435- let dep = find_workspace_dep ( dependency. toml_key ( ) , ws. root_manifest ( ) ) ?;
472+ let dep = find_workspace_dep (
473+ dependency. toml_key ( ) ,
474+ ws,
475+ ws. root_manifest ( ) ,
476+ ws. unstable_features ( ) ,
477+ ) ?;
436478 if let Some ( features) = dep. features . clone ( ) {
437479 dependency = dependency. set_inherited_features ( features) ;
438480 }
@@ -547,6 +589,8 @@ fn check_rust_version_for_optional_dependency(
547589/// If it doesn't exist but exists in another table, let's use that as most likely users
548590/// want to use the same version across all tables unless they are renaming.
549591fn get_existing_dependency (
592+ ws : & Workspace < ' _ > ,
593+ unstable_features : & Features ,
550594 manifest : & LocalManifest ,
551595 dep_key : & str ,
552596 section : & DepTable ,
@@ -561,7 +605,7 @@ fn get_existing_dependency(
561605 }
562606
563607 let mut possible: Vec < _ > = manifest
564- . get_dependency_versions ( dep_key)
608+ . get_dependency_versions ( dep_key, ws , unstable_features )
565609 . map ( |( path, dep) | {
566610 let key = if path == * section {
567611 ( Key :: Existing , true )
@@ -776,6 +820,11 @@ fn select_package(
776820 if let Some ( reg_name) = dependency. registry . as_deref ( ) {
777821 dep = dep. set_registry ( reg_name) ;
778822 }
823+ if let Some ( Source :: Path ( PathSource { base, .. } ) ) = dependency. source ( ) {
824+ if let Some ( Source :: Path ( dep_src) ) = & mut dep. source {
825+ dep_src. base = base. clone ( ) ;
826+ }
827+ }
779828 Ok ( dep)
780829 }
781830 _ => {
@@ -1107,7 +1156,12 @@ fn format_features_version_suffix(dep: &DependencyUI) -> String {
11071156 }
11081157}
11091158
1110- fn find_workspace_dep ( toml_key : & str , root_manifest : & Path ) -> CargoResult < Dependency > {
1159+ fn find_workspace_dep (
1160+ toml_key : & str ,
1161+ ws : & Workspace < ' _ > ,
1162+ root_manifest : & Path ,
1163+ unstable_features : & Features ,
1164+ ) -> CargoResult < Dependency > {
11111165 let manifest = LocalManifest :: try_new ( root_manifest) ?;
11121166 let manifest = manifest
11131167 . data
@@ -1127,7 +1181,14 @@ fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult<Depen
11271181 let dep_item = dependencies
11281182 . get ( toml_key)
11291183 . with_context ( || format ! ( "could not find {toml_key} in `workspace.dependencies`" ) ) ?;
1130- Dependency :: from_toml ( root_manifest. parent ( ) . unwrap ( ) , toml_key, dep_item)
1184+ Dependency :: from_toml (
1185+ ws. gctx ( ) ,
1186+ ws. root ( ) ,
1187+ root_manifest. parent ( ) . unwrap ( ) ,
1188+ unstable_features,
1189+ toml_key,
1190+ dep_item,
1191+ )
11311192}
11321193
11331194/// Convert a `semver::VersionReq` into a rendered `semver::Version` if all fields are fully
0 commit comments