diff --git a/src/bin/cargo/commands/add.rs b/src/bin/cargo/commands/add.rs index da821f328bd..4c9436df696 100644 --- a/src/bin/cargo/commands/add.rs +++ b/src/bin/cargo/commands/add.rs @@ -101,6 +101,12 @@ Example uses: .help("Filesystem path to local crate to add") .group("selected") .conflicts_with("git"), + clap::Arg::new("base") + .long("base") + .action(ArgAction::Set) + .value_name("BASE") + .help("The path base to use when adding from a local crate (unstable).") + .requires("path"), clap::Arg::new("git") .long("git") .action(ArgAction::Set) @@ -224,6 +230,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { fn parse_dependencies(gctx: &GlobalContext, matches: &ArgMatches) -> CargoResult> { let path = matches.get_one::("path"); + let base = matches.get_one::("base"); let git = matches.get_one::("git"); let branch = matches.get_one::("branch"); let rev = matches.get_one::("rev"); @@ -329,6 +336,7 @@ fn parse_dependencies(gctx: &GlobalContext, matches: &ArgMatches) -> CargoResult public, registry: registry.clone(), path: path.map(String::from), + base: base.map(String::from), git: git.map(String::from), branch: branch.map(String::from), rev: rev.map(String::from), diff --git a/src/bin/cargo/commands/remove.rs b/src/bin/cargo/commands/remove.rs index e74f53d6442..833fd00c549 100644 --- a/src/bin/cargo/commands/remove.rs +++ b/src/bin/cargo/commands/remove.rs @@ -167,20 +167,37 @@ fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> { let members = workspace .members() - .map(|p| LocalManifest::try_new(p.manifest_path())) + .map(|p| { + Ok(( + LocalManifest::try_new(p.manifest_path())?, + p.manifest().unstable_features(), + )) + }) .collect::>>()?; let mut dependencies = members - .iter() - .flat_map(|manifest| { - manifest.get_sections().into_iter().flat_map(|(_, table)| { - table - .as_table_like() - .unwrap() - .iter() - .map(|(key, item)| Dependency::from_toml(&manifest.path, key, item)) - .collect::>() - }) + .into_iter() + .flat_map(|(manifest, unstable_features)| { + manifest + .get_sections() + .into_iter() + .flat_map(move |(_, table)| { + table + .as_table_like() + .unwrap() + .iter() + .map(|(key, item)| { + Dependency::from_toml( + workspace.gctx(), + workspace.root(), + &manifest.path, + &unstable_features, + key, + item, + ) + }) + .collect::>() + }) }) .collect::>>()?; @@ -192,7 +209,14 @@ fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> { { deps_table.set_implicit(true); for (key, item) in deps_table.iter_mut() { - let ws_dep = Dependency::from_toml(&workspace.root(), key.get(), item)?; + let ws_dep = Dependency::from_toml( + workspace.gctx(), + workspace.root(), + &workspace.root(), + workspace.unstable_features(), + key.get(), + item, + )?; // search for uses of this workspace dependency let mut is_used = false; @@ -329,7 +353,14 @@ fn gc_unused_patches(workspace: &Workspace<'_>, resolve: &Resolve) -> CargoResul patch_table.set_implicit(true); for (key, item) in patch_table.iter_mut() { - let dep = Dependency::from_toml(&workspace.root_manifest(), key.get(), item)?; + let dep = Dependency::from_toml( + workspace.gctx(), + workspace.root(), + &workspace.root_manifest(), + workspace.unstable_features(), + key.get(), + item, + )?; // Generate a PackageIdSpec url for querying let url = if let MaybeWorkspace::Other(source_id) = diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index ad5d6f1230d..ac49f58e1d3 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -12,6 +12,7 @@ use std::str::FromStr; use anyhow::Context as _; use cargo_util::paths; use cargo_util_schemas::core::PartialVersion; +use cargo_util_schemas::manifest::PathBaseName; use cargo_util_schemas::manifest::RustVersion; use indexmap::IndexSet; use itertools::Itertools; @@ -20,6 +21,7 @@ use toml_edit::Item as TomlItem; use crate::core::dependency::DepKind; use crate::core::registry::PackageRegistry; use crate::core::FeatureValue; +use crate::core::Features; use crate::core::Package; use crate::core::Registry; use crate::core::Shell; @@ -28,6 +30,7 @@ use crate::core::Workspace; use crate::sources::source::QueryKind; use crate::util::cache_lock::CacheLockMode; use crate::util::style; +use crate::util::toml::lookup_path_base; use crate::util::toml_mut::dependency::Dependency; use crate::util::toml_mut::dependency::GitSource; use crate::util::toml_mut::dependency::MaybeWorkspace; @@ -197,7 +200,13 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<( print_dep_table_msg(&mut options.gctx.shell(), &dep)?; - manifest.insert_into_table(&dep_table, &dep)?; + manifest.insert_into_table( + &dep_table, + &dep, + workspace.gctx(), + workspace.root(), + options.spec.manifest().unstable_features(), + )?; if dep.optional == Some(true) { let is_namespaced_features_supported = check_rust_version_for_optional_dependency(options.spec.rust_version())?; @@ -270,8 +279,11 @@ pub struct DepOp { /// Registry for looking up dependency version pub registry: Option, - /// Git repo for dependency + /// File system path for dependency pub path: Option, + /// Specify a named base for a path dependency + pub base: Option, + /// Git repo for dependency pub git: Option, /// Specify an alternative git branch @@ -332,7 +344,19 @@ fn resolve_dependency( selected } else if let Some(raw_path) = &arg.path { let path = paths::normalize_path(&std::env::current_dir()?.join(raw_path)); - let src = PathSource::new(&path); + let mut src = PathSource::new(path); + src.base = arg.base.clone(); + + if let Some(base) = &arg.base { + // Validate that the base is valid. + let workspace_root = || Ok(ws.root_manifest().parent().unwrap()); + lookup_path_base( + &PathBaseName::new(base.clone())?, + &gctx, + &workspace_root, + spec.manifest().unstable_features(), + )?; + } let selected = if let Some(crate_spec) = &crate_spec { if let Some(v) = crate_spec.version_req() { @@ -349,9 +373,13 @@ fn resolve_dependency( } selected } else { - let mut source = crate::sources::PathSource::new(&path, src.source_id()?, gctx); + let mut source = crate::sources::PathSource::new(&src.path, src.source_id()?, gctx); let package = source.root_package()?; - Dependency::from(package.summary()) + let mut selected = Dependency::from(package.summary()); + if let Some(Source::Path(selected_src)) = &mut selected.source { + selected_src.base = src.base; + } + selected }; selected } else if let Some(crate_spec) = &crate_spec { @@ -361,9 +389,16 @@ fn resolve_dependency( }; selected_dep = populate_dependency(selected_dep, arg); - let lookup = |dep_key: &_| get_existing_dependency(manifest, dep_key, section); + let lookup = |dep_key: &_| { + get_existing_dependency( + ws, + spec.manifest().unstable_features(), + manifest, + dep_key, + section, + ) + }; let old_dep = fuzzy_lookup(&mut selected_dep, lookup, gctx)?; - let mut dependency = if let Some(mut old_dep) = old_dep.clone() { if old_dep.name != selected_dep.name { // Assuming most existing keys are not relevant when the package changes @@ -385,7 +420,9 @@ fn resolve_dependency( if dependency.source().is_none() { // Checking for a workspace dependency happens first since a member could be specified // in the workspace dependencies table as a dependency - let lookup = |toml_key: &_| Ok(find_workspace_dep(toml_key, ws.root_manifest()).ok()); + let lookup = |toml_key: &_| { + Ok(find_workspace_dep(toml_key, ws, ws.root_manifest(), ws.unstable_features()).ok()) + }; if let Some(_dep) = fuzzy_lookup(&mut dependency, lookup, gctx)? { dependency = dependency.set_source(WorkspaceSource::new()); } else if let Some(package) = ws.members().find(|p| p.name().as_str() == dependency.name) { @@ -432,7 +469,12 @@ fn resolve_dependency( let query = dependency.query(gctx)?; let query = match query { MaybeWorkspace::Workspace(_workspace) => { - let dep = find_workspace_dep(dependency.toml_key(), ws.root_manifest())?; + let dep = find_workspace_dep( + dependency.toml_key(), + ws, + ws.root_manifest(), + ws.unstable_features(), + )?; if let Some(features) = dep.features.clone() { dependency = dependency.set_inherited_features(features); } @@ -547,6 +589,8 @@ fn check_rust_version_for_optional_dependency( /// If it doesn't exist but exists in another table, let's use that as most likely users /// want to use the same version across all tables unless they are renaming. fn get_existing_dependency( + ws: &Workspace<'_>, + unstable_features: &Features, manifest: &LocalManifest, dep_key: &str, section: &DepTable, @@ -561,7 +605,7 @@ fn get_existing_dependency( } let mut possible: Vec<_> = manifest - .get_dependency_versions(dep_key) + .get_dependency_versions(dep_key, ws, unstable_features) .map(|(path, dep)| { let key = if path == *section { (Key::Existing, true) @@ -776,6 +820,11 @@ fn select_package( if let Some(reg_name) = dependency.registry.as_deref() { dep = dep.set_registry(reg_name); } + if let Some(Source::Path(PathSource { base, .. })) = dependency.source() { + if let Some(Source::Path(dep_src)) = &mut dep.source { + dep_src.base = base.clone(); + } + } Ok(dep) } _ => { @@ -1107,7 +1156,12 @@ fn format_features_version_suffix(dep: &DependencyUI) -> String { } } -fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult { +fn find_workspace_dep( + toml_key: &str, + ws: &Workspace<'_>, + root_manifest: &Path, + unstable_features: &Features, +) -> CargoResult { let manifest = LocalManifest::try_new(root_manifest)?; let manifest = manifest .data @@ -1127,7 +1181,14 @@ fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult>(); - for manifest_path in manifest_paths { + for (manifest_path, unstable_features) in items { trace!("updating TOML manifest at `{manifest_path:?}` with upgraded dependencies"); let crate_root = manifest_path @@ -417,7 +422,10 @@ pub fn write_manifest_upgrades( for (mut dep_key, dep_item) in dep_table.iter_mut() { let dep_key_str = dep_key.get(); let dependency = crate::util::toml_mut::dependency::Dependency::from_toml( + ws.gctx(), + ws.root(), &manifest_path, + unstable_features, dep_key_str, dep_item, )?; @@ -472,7 +480,14 @@ pub fn write_manifest_upgrades( dep.source = Some(Source::Registry(source)); trace!("upgrading dependency {name}"); - dep.update_toml(&crate_root, &mut dep_key, dep_item); + dep.update_toml( + ws.gctx(), + ws.root(), + &crate_root, + unstable_features, + &mut dep_key, + dep_item, + )?; manifest_has_changed = true; any_file_has_changed = true; } diff --git a/src/cargo/util/toml_mut/dependency.rs b/src/cargo/util/toml_mut/dependency.rs index ce7e6229021..b66fc56afbc 100644 --- a/src/cargo/util/toml_mut/dependency.rs +++ b/src/cargo/util/toml_mut/dependency.rs @@ -1,16 +1,19 @@ //! Information about dependencies in a manifest. +use std::borrow::Cow; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; +use cargo_util_schemas::manifest::PathBaseName; use indexmap::IndexSet; use itertools::Itertools; use toml_edit::KeyMut; use super::manifest::str_or_1_len_table; -use crate::core::GitReference; use crate::core::SourceId; use crate::core::Summary; +use crate::core::{Features, GitReference}; +use crate::util::toml::lookup_path_base; use crate::util::toml_mut::is_sorted; use crate::CargoResult; use crate::GlobalContext; @@ -219,7 +222,14 @@ pub enum MaybeWorkspace { impl Dependency { /// Create a dependency from a TOML table entry. - pub fn from_toml(crate_root: &Path, key: &str, item: &toml_edit::Item) -> CargoResult { + pub fn from_toml( + gctx: &GlobalContext, + workspace_root: &Path, + crate_root: &Path, + unstable_features: &Features, + key: &str, + item: &toml_edit::Item, + ) -> CargoResult { if let Some(version) = item.as_str() { let dep = Self::new(key).set_source(RegistrySource::new(version)); Ok(dep) @@ -266,12 +276,31 @@ impl Dependency { } src.into() } else if let Some(path) = table.get("path") { + let base = table + .get("base") + .map(|base| { + base.as_str() + .ok_or_else(|| invalid_type(key, "base", base.type_name(), "string")) + .map(|s| s.to_owned()) + }) + .transpose()?; + let relative_to = if let Some(base) = &base { + Cow::Owned(lookup_path_base( + &PathBaseName::new(base.clone())?, + gctx, + &|| Ok(workspace_root), + unstable_features, + )?) + } else { + Cow::Borrowed(crate_root) + }; let path = - crate_root + relative_to .join(path.as_str().ok_or_else(|| { invalid_type(key, "path", path.type_name(), "string") })?); let mut src = PathSource::new(path); + src.base = base; if let Some(value) = table.get("version") { src = src.set_version(value.as_str().ok_or_else(|| { invalid_type(key, "version", value.type_name(), "string") @@ -372,7 +401,13 @@ impl Dependency { /// # Panic /// /// Panics if the path is relative - pub fn to_toml(&self, crate_root: &Path) -> toml_edit::Item { + pub fn to_toml<'a>( + &self, + gctx: &GlobalContext, + workspace_root: &Path, + crate_root: &Path, + unstable_features: &Features, + ) -> CargoResult { assert!( crate_root.is_absolute(), "Absolute path needed, got: {}", @@ -412,10 +447,14 @@ impl Dependency { table.insert("version", src.version.as_str().into()); } Some(Source::Path(src)) => { - let relpath = path_field(crate_root, &src.path); + let relpath = + path_field(&src, gctx, workspace_root, crate_root, unstable_features)?; if let Some(r) = src.version.as_deref() { table.insert("version", r.into()); } + if let Some(base) = &src.base { + table.insert("base", base.into()); + } table.insert("path", relpath.into()); } Some(Source::Git(src)) => { @@ -465,19 +504,22 @@ impl Dependency { } }; - table + Ok(table) } /// Modify existing entry to match this dependency. - pub fn update_toml<'k>( + pub fn update_toml<'k, 'a>( &self, + gctx: &GlobalContext, + workspace_root: &Path, crate_root: &Path, + unstable_features: &Features, key: &mut KeyMut<'k>, item: &mut toml_edit::Item, - ) { + ) -> CargoResult<()> { if str_or_1_len_table(item) { // Little to preserve - let mut new_item = self.to_toml(crate_root); + let mut new_item = self.to_toml(gctx, workspace_root, crate_root, unstable_features)?; match (&item, &mut new_item) { (toml_edit::Item::Value(old), toml_edit::Item::Value(new)) => { *new.decor_mut() = old.decor().clone(); @@ -493,12 +535,18 @@ impl Dependency { Some(Source::Registry(src)) => { overwrite_value(table, "version", src.version.as_str()); - for key in ["path", "git", "branch", "tag", "rev", "workspace"] { + for key in ["path", "git", "branch", "tag", "rev", "workspace", "base"] { table.remove(key); } } Some(Source::Path(src)) => { - let relpath = path_field(crate_root, &src.path); + if let Some(base) = &src.base { + overwrite_value(table, "base", base); + } else { + table.remove("base"); + } + let relpath = + path_field(&src, gctx, workspace_root, crate_root, unstable_features)?; overwrite_value(table, "path", relpath); if let Some(r) = src.version.as_deref() { overwrite_value(table, "version", r); @@ -533,7 +581,7 @@ impl Dependency { table.remove("version"); } - for key in ["path", "workspace"] { + for key in ["path", "workspace", "base"] { table.remove(key); } } @@ -552,6 +600,7 @@ impl Dependency { "rev", "package", "default-features", + "base", ] { table.remove(key); } @@ -623,6 +672,7 @@ impl Dependency { } else { unreachable!("Invalid dependency type: {}", item.type_name()); } + Ok(()) } } @@ -682,10 +732,26 @@ impl From for Dependency { } } -fn path_field(crate_root: &Path, abs_path: &Path) -> String { - let relpath = pathdiff::diff_paths(abs_path, crate_root).expect("both paths are absolute"); +fn path_field<'a>( + source: &PathSource, + gctx: &GlobalContext, + workspace_root: &Path, + crate_root: &Path, + unstable_features: &Features, +) -> CargoResult { + let relative_to = if let Some(base) = &source.base { + Cow::Owned(lookup_path_base( + &PathBaseName::new(base.clone())?, + gctx, + &|| Ok(workspace_root), + unstable_features, + )?) + } else { + Cow::Borrowed(crate_root) + }; + let relpath = pathdiff::diff_paths(&source.path, relative_to).expect("both paths are absolute"); let relpath = relpath.to_str().unwrap().replace('\\', "/"); - relpath + Ok(relpath) } /// Primary location of a dependency. @@ -812,6 +878,8 @@ impl std::fmt::Display for RegistrySource { pub struct PathSource { /// Local, absolute path. pub path: PathBuf, + /// The path base, if using one. + pub base: Option, /// Version requirement for when published. pub version: Option, } @@ -821,6 +889,7 @@ impl PathSource { pub fn new(path: impl Into) -> Self { Self { path: path.into(), + base: None, version: None, } } @@ -975,11 +1044,14 @@ mod tests { paths::normalize_path(&std::env::current_dir().unwrap().join(Path::new("/"))); let dep = Dependency::new("dep").set_source(RegistrySource::new("1.0")); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -988,12 +1060,15 @@ mod tests { paths::normalize_path(&std::env::current_dir().unwrap().join(Path::new("/"))); let dep = Dependency::new("dep").set_source(RegistrySource::new("1.0")); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert_eq!(item.as_str(), Some("1.0")); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1004,7 +1079,10 @@ mod tests { .set_source(RegistrySource::new("1.0")) .set_optional(true); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert!(item.is_inline_table()); @@ -1012,7 +1090,7 @@ mod tests { let dep = item.as_inline_table().unwrap(); assert_eq!(dep.get("optional").unwrap().as_bool(), Some(true)); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1023,7 +1101,10 @@ mod tests { .set_source(RegistrySource::new("1.0")) .set_default_features(false); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert!(item.is_inline_table()); @@ -1031,7 +1112,7 @@ mod tests { let dep = item.as_inline_table().unwrap(); assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false)); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1040,7 +1121,10 @@ mod tests { let crate_root = root.join("foo"); let dep = Dependency::new("dep").set_source(PathSource::new(root.join("bar"))); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert!(item.is_inline_table()); @@ -1048,7 +1132,7 @@ mod tests { let dep = item.as_inline_table().unwrap(); assert_eq!(dep.get("path").unwrap().as_str(), Some("../bar")); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1057,7 +1141,10 @@ mod tests { paths::normalize_path(&std::env::current_dir().unwrap().join(Path::new("/"))); let dep = Dependency::new("dep").set_source(GitSource::new("https://foor/bar.git")); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert!(item.is_inline_table()); @@ -1068,7 +1155,7 @@ mod tests { Some("https://foor/bar.git") ); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1079,7 +1166,10 @@ mod tests { .set_source(RegistrySource::new("1.0")) .set_rename("d"); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "d".to_owned()); assert!(item.is_inline_table()); @@ -1087,7 +1177,7 @@ mod tests { let dep = item.as_inline_table().unwrap(); assert_eq!(dep.get("package").unwrap().as_str(), Some("dep")); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1098,7 +1188,10 @@ mod tests { .set_source(RegistrySource::new("1.0")) .set_registry("alternative"); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "dep".to_owned()); assert!(item.is_inline_table()); @@ -1106,7 +1199,7 @@ mod tests { let dep = item.as_inline_table().unwrap(); assert_eq!(dep.get("registry").unwrap().as_str(), Some("alternative")); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1118,7 +1211,10 @@ mod tests { .set_default_features(false) .set_rename("d"); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); assert_eq!(key, "d".to_owned()); assert!(item.is_inline_table()); @@ -1128,7 +1224,7 @@ mod tests { assert_eq!(dep.get("version").unwrap().as_str(), Some("1.0")); assert_eq!(dep.get("default-features").unwrap().as_bool(), Some(false)); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1139,13 +1235,16 @@ mod tests { let relpath = "sibling/crate"; let dep = Dependency::new("dep").set_source(PathSource::new(path)); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); let table = item.as_inline_table().unwrap(); let got = table.get("path").unwrap().as_str().unwrap(); assert_eq!(got, relpath); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[test] @@ -1159,10 +1258,21 @@ mod tests { manifest, }; assert_eq!(local.manifest.to_string(), toml); + let gctx = GlobalContext::default().unwrap(); for (key, item) in local.data.clone().iter() { - let dep = Dependency::from_toml(&crate_root, key, item).unwrap(); + let dep = Dependency::from_toml( + &gctx, + &crate_root, + &crate_root, + &Features::default(), + key, + item, + ) + .unwrap(); let dep = dep.set_source(WorkspaceSource::new()); - local.insert_into_table(&vec![], &dep).unwrap(); + local + .insert_into_table(&vec![], &dep, &gctx, &crate_root, &Features::default()) + .unwrap(); assert_eq!(local.data.to_string(), "dep.workspace = true\n"); } } @@ -1176,20 +1286,38 @@ mod tests { let should_be = "sibling/crate"; let dep = Dependency::new("dep").set_source(PathSource::new(original)); let key = dep.toml_key(); - let item = dep.to_toml(&crate_root); + let gctx = GlobalContext::default().unwrap(); + let item = dep + .to_toml(&gctx, &crate_root, &crate_root, &Features::default()) + .unwrap(); let table = item.as_inline_table().unwrap(); let got = table.get("path").unwrap().as_str().unwrap(); assert_eq!(got, should_be); - verify_roundtrip(&crate_root, key, &item); + verify_roundtrip(&crate_root, &gctx, key, &item); } #[track_caller] - fn verify_roundtrip(crate_root: &Path, key: &str, item: &toml_edit::Item) { - let roundtrip = Dependency::from_toml(crate_root, key, item).unwrap(); + fn verify_roundtrip( + crate_root: &Path, + gctx: &GlobalContext, + key: &str, + item: &toml_edit::Item, + ) { + let roundtrip = Dependency::from_toml( + gctx, + crate_root, + crate_root, + &Features::default(), + key, + item, + ) + .unwrap(); let round_key = roundtrip.toml_key(); - let round_item = roundtrip.to_toml(crate_root); + let round_item = roundtrip + .to_toml(gctx, crate_root, crate_root, &Features::default()) + .unwrap(); assert_eq!(key, round_key); assert_eq!(item.to_string(), round_item.to_string()); } diff --git a/src/cargo/util/toml_mut/manifest.rs b/src/cargo/util/toml_mut/manifest.rs index d7ed18440d2..e166a24f2be 100644 --- a/src/cargo/util/toml_mut/manifest.rs +++ b/src/cargo/util/toml_mut/manifest.rs @@ -8,9 +8,9 @@ use anyhow::Context as _; use super::dependency::Dependency; use crate::core::dependency::DepKind; -use crate::core::FeatureValue; +use crate::core::{FeatureValue, Features, Workspace}; use crate::util::interning::InternedString; -use crate::CargoResult; +use crate::{CargoResult, GlobalContext}; /// Dependency table to add deps to. #[derive(Clone, Debug, PartialEq, Eq)] @@ -286,6 +286,8 @@ impl LocalManifest { pub fn get_dependency_versions<'s>( &'s self, dep_key: &'s str, + ws: &'s Workspace<'_>, + unstable_features: &'s Features, ) -> impl Iterator)> + 's { let crate_root = self.path.parent().expect("manifest path is absolute"); self.get_sections() @@ -307,7 +309,14 @@ impl LocalManifest { }) .flatten() .map(move |(table_path, dep_key, dep_item)| { - let dep = Dependency::from_toml(crate_root, &dep_key, &dep_item); + let dep = Dependency::from_toml( + ws.gctx(), + ws.root(), + crate_root, + unstable_features, + &dep_key, + &dep_item, + ); (table_path, dep) }) } @@ -317,6 +326,9 @@ impl LocalManifest { &mut self, table_path: &[String], dep: &Dependency, + gctx: &GlobalContext, + workspace_root: &Path, + unstable_features: &Features, ) -> CargoResult<()> { let crate_root = self .path @@ -331,7 +343,14 @@ impl LocalManifest { .unwrap() .get_key_value_mut(dep_key) { - dep.update_toml(&crate_root, &mut dep_key, dep_item); + dep.update_toml( + gctx, + workspace_root, + &crate_root, + unstable_features, + &mut dep_key, + dep_item, + )?; if let Some(table) = dep_item.as_inline_table_mut() { // So long as we don't have `Cargo.toml` auto-formatting and inline-tables can only // be on one line, there isn't really much in the way of interesting formatting to @@ -339,7 +358,8 @@ impl LocalManifest { table.fmt(); } } else { - let new_dependency = dep.to_toml(&crate_root); + let new_dependency = + dep.to_toml(gctx, workspace_root, &crate_root, unstable_features)?; table[dep_key] = new_dependency; } diff --git a/src/doc/man/cargo-add.md b/src/doc/man/cargo-add.md index 1c0b736af90..555c96b064e 100644 --- a/src/doc/man/cargo-add.md +++ b/src/doc/man/cargo-add.md @@ -63,6 +63,12 @@ Specific commit to use when adding from git. [Filesystem path](../reference/specifying-dependencies.html#specifying-path-dependencies) to local crate to add. {{/option}} +{{#option "`--base` _base_" }} +The [path base](../reference/unstable.html#path-bases) to use when adding a local crate. + +[Unstable (nightly-only)](../reference/unstable.html#path-bases) +{{/option}} + {{> options-registry }} {{/options}} diff --git a/src/doc/man/generated_txt/cargo-add.txt b/src/doc/man/generated_txt/cargo-add.txt index 33c536f8321..70757246ec2 100644 --- a/src/doc/man/generated_txt/cargo-add.txt +++ b/src/doc/man/generated_txt/cargo-add.txt @@ -56,6 +56,14 @@ OPTIONS to local crate to add. + --base base + The path base + + to use when adding a local crate. + + Unstable (nightly-only) + + --registry registry Name of the registry to use. Registry names are defined in Cargo config files diff --git a/src/doc/src/commands/cargo-add.md b/src/doc/src/commands/cargo-add.md index 774ca41edfa..e61f8408eb8 100644 --- a/src/doc/src/commands/cargo-add.md +++ b/src/doc/src/commands/cargo-add.md @@ -59,6 +59,11 @@ dependency will be listed in the command's output.
Filesystem path to local crate to add.
+
--base base
+
The path base to use when adding a local crate.

+

Unstable (nightly-only)

+ +
--registry registry
Name of the registry to use. Registry names are defined in Cargo config files. If not specified, the default registry is used, diff --git a/src/etc/man/cargo-add.1 b/src/etc/man/cargo-add.1 index b89508b3f09..a7b2d1a110d 100644 --- a/src/etc/man/cargo-add.1 +++ b/src/etc/man/cargo-add.1 @@ -74,6 +74,13 @@ Specific commit to use when adding from git. \fIFilesystem path\fR to local crate to add. .RE .sp +\fB\-\-base\fR \fIbase\fR +.RS 4 +The \fIpath base\fR to use when adding a local crate. +.sp +\fIUnstable (nightly\-only)\fR +.RE +.sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/.cargo/config.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/.cargo/config.toml new file mode 100644 index 00000000000..fa0f7bb4d2b --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "deps" diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/Cargo.toml new file mode 100644 index 00000000000..32f9a4ec1cd --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/Cargo.toml @@ -0,0 +1,7 @@ +cargo-features = ["path-bases"] + +[workspace] +members = ["primary", "deps/dependency"] + +[workspace.dependencies] +foo = { version = "0.0.0", base = "my_base", path = "./dependency"} \ No newline at end of file diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/deps/dependency/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/deps/dependency/Cargo.toml new file mode 100644 index 00000000000..0de6f9b15a8 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/deps/dependency/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "foo" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/deps/dependency/src/lib.rs b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/deps/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/primary/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/primary/Cargo.toml new file mode 100644 index 00000000000..737232cece6 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/primary/Cargo.toml @@ -0,0 +1,6 @@ +cargo-features = ["path-bases"] + +[package] +name = "bar" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/primary/src/lib.rs b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/mod.rs b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/mod.rs new file mode 100644 index 00000000000..95ecd0d6500 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/mod.rs @@ -0,0 +1,27 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .args(["foo", "-p", "bar"]) + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .success() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/Cargo.toml new file mode 100644 index 00000000000..32f9a4ec1cd --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/Cargo.toml @@ -0,0 +1,7 @@ +cargo-features = ["path-bases"] + +[workspace] +members = ["primary", "deps/dependency"] + +[workspace.dependencies] +foo = { version = "0.0.0", base = "my_base", path = "./dependency"} \ No newline at end of file diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/deps/dependency/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/deps/dependency/Cargo.toml new file mode 100644 index 00000000000..0de6f9b15a8 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/deps/dependency/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "foo" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/primary/Cargo.toml b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/primary/Cargo.toml new file mode 100644 index 00000000000..67ed3895785 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/out/primary/Cargo.toml @@ -0,0 +1,9 @@ +cargo-features = ["path-bases"] + +[package] +name = "bar" +version = "0.0.0" +edition = "2015" + +[dependencies] +foo.workspace = true diff --git a/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/stderr.term.svg b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/stderr.term.svg new file mode 100644 index 00000000000..890a67bc986 --- /dev/null +++ b/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/stderr.term.svg @@ -0,0 +1,27 @@ + + + + + + + Adding foo (workspace) to dependencies + + + + + + diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/in/.cargo/config.toml b/tests/testsuite/cargo_add/dev_existing_path_base/in/.cargo/config.toml new file mode 100644 index 00000000000..4539a438423 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "." diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/in/dependency/Cargo.toml b/tests/testsuite/cargo_add/dev_existing_path_base/in/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/in/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/in/dependency/src/lib.rs b/tests/testsuite/cargo_add/dev_existing_path_base/in/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/in/primary/Cargo.toml b/tests/testsuite/cargo_add/dev_existing_path_base/in/primary/Cargo.toml new file mode 100644 index 00000000000..ecba72b5df6 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/in/primary/Cargo.toml @@ -0,0 +1,11 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { version = "0.0.0", base = "my_base", path = "dependency" } diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/in/primary/src/lib.rs b/tests/testsuite/cargo_add/dev_existing_path_base/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/mod.rs b/tests/testsuite/cargo_add/dev_existing_path_base/mod.rs new file mode 100644 index 00000000000..be1a8550392 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("cargo-list-test-fixture-dependency --dev") + .current_dir(&cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .success() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/out/dependency/Cargo.toml b/tests/testsuite/cargo_add/dev_existing_path_base/out/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/out/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/out/primary/Cargo.toml b/tests/testsuite/cargo_add/dev_existing_path_base/out/primary/Cargo.toml new file mode 100644 index 00000000000..6f036f2f6b9 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/out/primary/Cargo.toml @@ -0,0 +1,14 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { version = "0.0.0", base = "my_base", path = "dependency" } + +[dev-dependencies] +cargo-list-test-fixture-dependency = { base = "my_base", path = "dependency" } diff --git a/tests/testsuite/cargo_add/dev_existing_path_base/stderr.term.svg b/tests/testsuite/cargo_add/dev_existing_path_base/stderr.term.svg new file mode 100644 index 00000000000..c4a8bc01449 --- /dev/null +++ b/tests/testsuite/cargo_add/dev_existing_path_base/stderr.term.svg @@ -0,0 +1,29 @@ + + + + + + + Adding cargo-list-test-fixture-dependency (local) to dev-dependencies + + Locking 1 package to latest compatible version + + + + + + diff --git a/tests/testsuite/cargo_add/help/stdout.term.svg b/tests/testsuite/cargo_add/help/stdout.term.svg index 9335d606113..cee4d65c49f 100644 --- a/tests/testsuite/cargo_add/help/stdout.term.svg +++ b/tests/testsuite/cargo_add/help/stdout.term.svg @@ -219,83 +219,89 @@ - --git <URI> + --base <BASE> - Git repository location + The path base to use when adding from a local crate (unstable). - + - Without any other information, cargo will use latest commit on the main branch. + --git <URI> - + Git repository location - --branch <BRANCH> + - Git branch to download the crate from + Without any other information, cargo will use latest commit on the main branch. - --tag <TAG> + --branch <BRANCH> - Git tag to download the crate from + Git branch to download the crate from - --rev <REV> + --tag <TAG> - Git reference to download the crate from + Git tag to download the crate from - + - This is the catch all, handling hashes to named references in remote repositories. + --rev <REV> - + Git reference to download the crate from - --registry <NAME> + - Package registry for this dependency + This is the catch all, handling hashes to named references in remote repositories. - Section: + --registry <NAME> - --dev + Package registry for this dependency - Add as development dependency + - + Section: - Dev-dependencies are not used when compiling a package for building, but are used for + --dev - compiling tests, examples, and benchmarks. + Add as development dependency - These dependencies are not propagated to other packages which depend on this package. + Dev-dependencies are not used when compiling a package for building, but are used for - + compiling tests, examples, and benchmarks. - --build + - Add as build dependency + These dependencies are not propagated to other packages which depend on this package. - + - Build-dependencies are the only dependencies available for use by build scripts + --build - (`build.rs` files). + Add as build dependency - + - --target <TARGET> + Build-dependencies are the only dependencies available for use by build scripts - Add as dependency to the given target platform + (`build.rs` files). - Run `cargo help add` for more detailed information. + --target <TARGET> - + Add as dependency to the given target platform + + + + Run `cargo help add` for more detailed information. + + diff --git a/tests/testsuite/cargo_add/mod.rs b/tests/testsuite/cargo_add/mod.rs index 8207d5fd387..ff910628ee8 100644 --- a/tests/testsuite/cargo_add/mod.rs +++ b/tests/testsuite/cargo_add/mod.rs @@ -16,9 +16,11 @@ mod detect_workspace_inherit; mod detect_workspace_inherit_features; mod detect_workspace_inherit_fuzzy; mod detect_workspace_inherit_optional; +mod detect_workspace_inherit_path_base; mod detect_workspace_inherit_public; mod dev; mod dev_build_conflict; +mod dev_existing_path_base; mod dev_prefer_existing_version; mod dry_run; mod empty_dep_name; @@ -94,6 +96,7 @@ mod overwrite_no_public_with_public; mod overwrite_optional; mod overwrite_optional_with_no_optional; mod overwrite_optional_with_optional; +mod overwrite_path_base_with_version; mod overwrite_path_noop; mod overwrite_path_with_version; mod overwrite_preserves_inline_table; @@ -108,6 +111,10 @@ mod overwrite_with_rename; mod overwrite_workspace_dep; mod overwrite_workspace_dep_features; mod path; +mod path_base; +mod path_base_inferred_name; +mod path_base_missing_base_path; +mod path_base_unstable; mod path_dev; mod path_inferred_name; mod path_inferred_name_conflicts_full_feature; diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/.cargo/config.toml b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/.cargo/config.toml new file mode 100644 index 00000000000..4539a438423 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "." diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/dependency/Cargo.toml b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/dependency/src/lib.rs b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/Cargo.toml b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/Cargo.toml new file mode 100644 index 00000000000..9d01c094369 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/Cargo.toml @@ -0,0 +1,11 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { optional = true, path = "dependency", base = "my_base" } diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/src/lib.rs b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/mod.rs b/tests/testsuite/cargo_add/overwrite_path_base_with_version/mod.rs new file mode 100644 index 00000000000..ade44c07b48 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/mod.rs @@ -0,0 +1,29 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", "20.0.0") + .publish(); + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("cargo-list-test-fixture-dependency@20.0") + .current_dir(&cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .success() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/dependency/Cargo.toml b/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/primary/Cargo.toml b/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/primary/Cargo.toml new file mode 100644 index 00000000000..ead3ec39232 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/primary/Cargo.toml @@ -0,0 +1,14 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { optional = true, version = "20.0" } + +[features] +cargo-list-test-fixture-dependency = ["dep:cargo-list-test-fixture-dependency"] diff --git a/tests/testsuite/cargo_add/overwrite_path_base_with_version/stderr.term.svg b/tests/testsuite/cargo_add/overwrite_path_base_with_version/stderr.term.svg new file mode 100644 index 00000000000..ea8afda68de --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/stderr.term.svg @@ -0,0 +1,35 @@ + + + + + + + Updating `dummy-registry` index + + Adding cargo-list-test-fixture-dependency v20.0 to optional dependencies + + Adding feature `cargo-list-test-fixture-dependency` + + Locking 1 package to latest compatible version + + + + + + diff --git a/tests/testsuite/cargo_add/path_base/in/.cargo/config.toml b/tests/testsuite/cargo_add/path_base/in/.cargo/config.toml new file mode 100644 index 00000000000..4539a438423 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "." diff --git a/tests/testsuite/cargo_add/path_base/in/dependency/Cargo.toml b/tests/testsuite/cargo_add/path_base/in/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/in/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base/in/dependency/src/lib.rs b/tests/testsuite/cargo_add/path_base/in/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base/in/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base/in/primary/Cargo.toml new file mode 100644 index 00000000000..420ef1eb8f7 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/in/primary/Cargo.toml @@ -0,0 +1,8 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base/in/primary/src/lib.rs b/tests/testsuite/cargo_add/path_base/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base/mod.rs b/tests/testsuite/cargo_add/path_base/mod.rs new file mode 100644 index 00000000000..326a76283bc --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("cargo-list-test-fixture-dependency --path ../dependency --base my_base") + .current_dir(&cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .success() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/path_base/out/dependency/Cargo.toml b/tests/testsuite/cargo_add/path_base/out/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/out/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base/out/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base/out/primary/Cargo.toml new file mode 100644 index 00000000000..ecba72b5df6 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/out/primary/Cargo.toml @@ -0,0 +1,11 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { version = "0.0.0", base = "my_base", path = "dependency" } diff --git a/tests/testsuite/cargo_add/path_base/stderr.term.svg b/tests/testsuite/cargo_add/path_base/stderr.term.svg new file mode 100644 index 00000000000..6781757da4a --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/stderr.term.svg @@ -0,0 +1,29 @@ + + + + + + + Adding cargo-list-test-fixture-dependency (local) to dependencies + + Locking 1 package to latest compatible version + + + + + + diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/in/.cargo/config.toml b/tests/testsuite/cargo_add/path_base_inferred_name/in/.cargo/config.toml new file mode 100644 index 00000000000..4539a438423 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "." diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/in/dependency/Cargo.toml b/tests/testsuite/cargo_add/path_base_inferred_name/in/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/in/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/in/dependency/src/lib.rs b/tests/testsuite/cargo_add/path_base_inferred_name/in/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/Cargo.toml new file mode 100644 index 00000000000..420ef1eb8f7 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/Cargo.toml @@ -0,0 +1,8 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/src/lib.rs b/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/mod.rs b/tests/testsuite/cargo_add/path_base_inferred_name/mod.rs new file mode 100644 index 00000000000..005a9d75330 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("--path ../dependency --base my_base") + .current_dir(&cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .success() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/out/dependency/Cargo.toml b/tests/testsuite/cargo_add/path_base_inferred_name/out/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/out/dependency/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture-dependency" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/out/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_inferred_name/out/primary/Cargo.toml new file mode 100644 index 00000000000..ecba72b5df6 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/out/primary/Cargo.toml @@ -0,0 +1,11 @@ +cargo-features = ["path-bases"] + +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { version = "0.0.0", base = "my_base", path = "dependency" } diff --git a/tests/testsuite/cargo_add/path_base_inferred_name/stderr.term.svg b/tests/testsuite/cargo_add/path_base_inferred_name/stderr.term.svg new file mode 100644 index 00000000000..6781757da4a --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/stderr.term.svg @@ -0,0 +1,29 @@ + + + + + + + Adding cargo-list-test-fixture-dependency (local) to dependencies + + Locking 1 package to latest compatible version + + + + + + diff --git a/tests/testsuite/cargo_add/path_base_missing_base_path/in/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_missing_base_path/in/primary/Cargo.toml new file mode 100644 index 00000000000..1622ce604fd --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/in/primary/Cargo.toml @@ -0,0 +1,6 @@ +cargo-features = ["path-bases"] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_missing_base_path/in/primary/src/lib.rs b/tests/testsuite/cargo_add/path_base_missing_base_path/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base_missing_base_path/mod.rs b/tests/testsuite/cargo_add/path_base_missing_base_path/mod.rs new file mode 100644 index 00000000000..dbae05ad0a4 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("--path dependency --base bad_base") + .current_dir(&cwd) + .masquerade_as_nightly_cargo(&["path-base"]) + .assert() + .code(101) + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/path_base_missing_base_path/out/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_missing_base_path/out/primary/Cargo.toml new file mode 100644 index 00000000000..1622ce604fd --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/out/primary/Cargo.toml @@ -0,0 +1,6 @@ +cargo-features = ["path-bases"] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_missing_base_path/stderr.term.svg b/tests/testsuite/cargo_add/path_base_missing_base_path/stderr.term.svg new file mode 100644 index 00000000000..ebe52195f6c --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/stderr.term.svg @@ -0,0 +1,27 @@ + + + + + + + error: path base `bad_base` is undefined. You must add an entry for `bad_base` in the Cargo configuration [path-bases] table. + + + + + + diff --git a/tests/testsuite/cargo_add/path_base_unstable/in/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_unstable/in/primary/Cargo.toml new file mode 100644 index 00000000000..8194d1deb0e --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_unstable/in/primary/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_unstable/in/primary/src/lib.rs b/tests/testsuite/cargo_add/path_base_unstable/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/path_base_unstable/mod.rs b/tests/testsuite/cargo_add/path_base_unstable/mod.rs new file mode 100644 index 00000000000..c55fa83a123 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_unstable/mod.rs @@ -0,0 +1,24 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::prelude::*; +use cargo_test_support::str; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = project_root.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("--path dependency --base mybase") + .current_dir(&cwd) + .assert() + .code(101) + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/path_base_unstable/out/primary/Cargo.toml b/tests/testsuite/cargo_add/path_base_unstable/out/primary/Cargo.toml new file mode 100644 index 00000000000..8194d1deb0e --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_unstable/out/primary/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/path_base_unstable/stderr.term.svg b/tests/testsuite/cargo_add/path_base_unstable/stderr.term.svg new file mode 100644 index 00000000000..ca60ce2b30e --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_unstable/stderr.term.svg @@ -0,0 +1,37 @@ + + + + + + + error: feature `path-bases` is required + + + + The package requires the Cargo feature called `path-bases`, but that feature is not stabilized in this version of Cargo ([..]). + + Consider trying a newer version of Cargo (this may require the nightly release). + + See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#path-bases for more information about the status of this feature. + + + + + + + +