Implement path-bases (RFC 3529) 2/n: cargo add support

RFC: https://github.com/rust-lang/rfcs/pull/3529
Tracking Issue: https://github.com/rust-lang/cargo/issues/14355

This PR adds the `--base` option to `cargo add` to allow adding a path dependency with a path base.
This commit is contained in:
Daniel Paoliello 2024-01-03 14:24:11 -08:00
parent e86545014c
commit 8de55540f0
69 changed files with 1008 additions and 110 deletions

View File

@ -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<Vec<DepOp>> {
let path = matches.get_one::<String>("path");
let base = matches.get_one::<String>("base");
let git = matches.get_one::<String>("git");
let branch = matches.get_one::<String>("branch");
let rev = matches.get_one::<String>("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),

View File

@ -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::<CargoResult<Vec<_>>>()?;
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::<Vec<_>>()
})
.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::<Vec<_>>()
})
})
.collect::<CargoResult<Vec<_>>>()?;
@ -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) =

View File

@ -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<String>,
/// Git repo for dependency
/// File system path for dependency
pub path: Option<String>,
/// Specify a named base for a path dependency
pub base: Option<String>,
/// Git repo for dependency
pub git: Option<String>,
/// 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<Dependency> {
fn find_workspace_dep(
toml_key: &str,
ws: &Workspace<'_>,
root_manifest: &Path,
unstable_features: &Features,
) -> CargoResult<Dependency> {
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<Depen
let dep_item = dependencies
.get(toml_key)
.with_context(|| format!("could not find {toml_key} in `workspace.dependencies`"))?;
Dependency::from_toml(root_manifest.parent().unwrap(), toml_key, dep_item)
Dependency::from_toml(
ws.gctx(),
ws.root(),
root_manifest.parent().unwrap(),
unstable_features,
toml_key,
dep_item,
)
}
/// Convert a `semver::VersionReq` into a rendered `semver::Version` if all fields are fully

View File

@ -398,11 +398,16 @@ pub fn write_manifest_upgrades(
let mut any_file_has_changed = false;
let manifest_paths = std::iter::once(ws.root_manifest())
.chain(ws.members().map(|member| member.manifest_path()))
let items = std::iter::once((ws.root_manifest(), ws.unstable_features()))
.chain(ws.members().map(|member| {
(
member.manifest_path(),
member.manifest().unstable_features(),
)
}))
.collect::<Vec<_>>();
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;
}

View File

@ -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<T> {
impl Dependency {
/// Create a dependency from a TOML table entry.
pub fn from_toml(crate_root: &Path, key: &str, item: &toml_edit::Item) -> CargoResult<Self> {
pub fn from_toml(
gctx: &GlobalContext,
workspace_root: &Path,
crate_root: &Path,
unstable_features: &Features,
key: &str,
item: &toml_edit::Item,
) -> CargoResult<Self> {
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<toml_edit::Item> {
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<Summary> 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<String> {
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<String>,
/// Version requirement for when published.
pub version: Option<String>,
}
@ -821,6 +889,7 @@ impl PathSource {
pub fn new(path: impl Into<PathBuf>) -> 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());
}

View File

@ -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<Item = (DepTable, CargoResult<Dependency>)> + '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;
}

View File

@ -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}}

View File

@ -56,6 +56,14 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies>
to local crate to add.
--base base
The path base
<https://doc.rust-lang.org/cargo/reference/unstable.html#path-bases>
to use when adding a local crate.
Unstable (nightly-only)
<https://doc.rust-lang.org/cargo/reference/unstable.html#path-bases>
--registry registry
Name of the registry to use. Registry names are defined in Cargo
config files

View File

@ -59,6 +59,11 @@ dependency will be listed in the command's output.
<dd class="option-desc"><a href="../reference/specifying-dependencies.html#specifying-path-dependencies">Filesystem path</a> to local crate to add.</dd>
<dt class="option-term" id="option-cargo-add---base"><a class="option-anchor" href="#option-cargo-add---base"></a><code>--base</code> <em>base</em></dt>
<dd class="option-desc">The <a href="../reference/unstable.html#path-bases">path base</a> to use when adding a local crate.</p>
<p><a href="../reference/unstable.html#path-bases">Unstable (nightly-only)</a></dd>
<dt class="option-term" id="option-cargo-add---registry"><a class="option-anchor" href="#option-cargo-add---registry"></a><code>--registry</code> <em>registry</em></dt>
<dd class="option-desc">Name of the registry to use. Registry names are defined in <a href="../reference/config.html">Cargo config
files</a>. If not specified, the default registry is used,

View File

@ -74,6 +74,13 @@ Specific commit to use when adding from git.
\fIFilesystem path\fR <https://doc.rust\-lang.org/cargo/reference/specifying\-dependencies.html#specifying\-path\-dependencies> to local crate to add.
.RE
.sp
\fB\-\-base\fR \fIbase\fR
.RS 4
The \fIpath base\fR <https://doc.rust\-lang.org/cargo/reference/unstable.html#path\-bases> to use when adding a local crate.
.sp
\fIUnstable (nightly\-only)\fR <https://doc.rust\-lang.org/cargo/reference/unstable.html#path\-bases>
.RE
.sp
\fB\-\-registry\fR \fIregistry\fR
.RS 4
Name of the registry to use. Registry names are defined in \fICargo config

View File

@ -0,0 +1,2 @@
[path-bases]
my_base = "deps"

View File

@ -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"}

View File

@ -0,0 +1,4 @@
[package]
name = "foo"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,6 @@
cargo-features = ["path-bases"]
[package]
name = "bar"
version = "0.0.0"
edition = "2015"

View File

@ -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);
}

View File

@ -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"}

View File

@ -0,0 +1,4 @@
[package]
name = "foo"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,9 @@
cargo-features = ["path-bases"]
[package]
name = "bar"
version = "0.0.0"
edition = "2015"
[dependencies]
foo.workspace = true

View File

@ -0,0 +1,27 @@
<svg width="740px" height="56px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-green { fill: #00AA00 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Adding</tspan><tspan> foo (workspace) to dependencies</tspan>
</tspan>
<tspan x="10px" y="46px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 738 B

View File

@ -0,0 +1,2 @@
[path-bases]
my_base = "."

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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" }

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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" }

View File

@ -0,0 +1,29 @@
<svg width="740px" height="74px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-green { fill: #00AA00 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Adding</tspan><tspan> cargo-list-test-fixture-dependency (local) to dev-dependencies</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest compatible version</tspan>
</tspan>
<tspan x="10px" y="64px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 911 B

View File

@ -219,83 +219,89 @@
</tspan>
<tspan x="10px" y="1810px">
</tspan>
<tspan x="10px" y="1828px"><tspan> </tspan><tspan class="fg-cyan bold">--git</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;URI&gt;</tspan>
<tspan x="10px" y="1828px"><tspan> </tspan><tspan class="fg-cyan bold">--base</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;BASE&gt;</tspan>
</tspan>
<tspan x="10px" y="1846px"><tspan> Git repository location</tspan>
<tspan x="10px" y="1846px"><tspan> The path base to use when adding from a local crate (unstable).</tspan>
</tspan>
<tspan x="10px" y="1864px"><tspan> </tspan>
<tspan x="10px" y="1864px">
</tspan>
<tspan x="10px" y="1882px"><tspan> Without any other information, cargo will use latest commit on the main branch.</tspan>
<tspan x="10px" y="1882px"><tspan> </tspan><tspan class="fg-cyan bold">--git</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;URI&gt;</tspan>
</tspan>
<tspan x="10px" y="1900px">
<tspan x="10px" y="1900px"><tspan> Git repository location</tspan>
</tspan>
<tspan x="10px" y="1918px"><tspan> </tspan><tspan class="fg-cyan bold">--branch</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;BRANCH&gt;</tspan>
<tspan x="10px" y="1918px"><tspan> </tspan>
</tspan>
<tspan x="10px" y="1936px"><tspan> Git branch to download the crate from</tspan>
<tspan x="10px" y="1936px"><tspan> Without any other information, cargo will use latest commit on the main branch.</tspan>
</tspan>
<tspan x="10px" y="1954px">
</tspan>
<tspan x="10px" y="1972px"><tspan> </tspan><tspan class="fg-cyan bold">--tag</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;TAG&gt;</tspan>
<tspan x="10px" y="1972px"><tspan> </tspan><tspan class="fg-cyan bold">--branch</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;BRANCH&gt;</tspan>
</tspan>
<tspan x="10px" y="1990px"><tspan> Git tag to download the crate from</tspan>
<tspan x="10px" y="1990px"><tspan> Git branch to download the crate from</tspan>
</tspan>
<tspan x="10px" y="2008px">
</tspan>
<tspan x="10px" y="2026px"><tspan> </tspan><tspan class="fg-cyan bold">--rev</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;REV&gt;</tspan>
<tspan x="10px" y="2026px"><tspan> </tspan><tspan class="fg-cyan bold">--tag</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;TAG&gt;</tspan>
</tspan>
<tspan x="10px" y="2044px"><tspan> Git reference to download the crate from</tspan>
<tspan x="10px" y="2044px"><tspan> Git tag to download the crate from</tspan>
</tspan>
<tspan x="10px" y="2062px"><tspan> </tspan>
<tspan x="10px" y="2062px">
</tspan>
<tspan x="10px" y="2080px"><tspan> This is the catch all, handling hashes to named references in remote repositories.</tspan>
<tspan x="10px" y="2080px"><tspan> </tspan><tspan class="fg-cyan bold">--rev</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;REV&gt;</tspan>
</tspan>
<tspan x="10px" y="2098px">
<tspan x="10px" y="2098px"><tspan> Git reference to download the crate from</tspan>
</tspan>
<tspan x="10px" y="2116px"><tspan> </tspan><tspan class="fg-cyan bold">--registry</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan>
<tspan x="10px" y="2116px"><tspan> </tspan>
</tspan>
<tspan x="10px" y="2134px"><tspan> Package registry for this dependency</tspan>
<tspan x="10px" y="2134px"><tspan> This is the catch all, handling hashes to named references in remote repositories.</tspan>
</tspan>
<tspan x="10px" y="2152px">
</tspan>
<tspan x="10px" y="2170px"><tspan class="fg-green bold">Section:</tspan>
<tspan x="10px" y="2170px"><tspan> </tspan><tspan class="fg-cyan bold">--registry</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan>
</tspan>
<tspan x="10px" y="2188px"><tspan> </tspan><tspan class="fg-cyan bold">--dev</tspan>
<tspan x="10px" y="2188px"><tspan> Package registry for this dependency</tspan>
</tspan>
<tspan x="10px" y="2206px"><tspan> Add as development dependency</tspan>
<tspan x="10px" y="2206px">
</tspan>
<tspan x="10px" y="2224px"><tspan> </tspan>
<tspan x="10px" y="2224px"><tspan class="fg-green bold">Section:</tspan>
</tspan>
<tspan x="10px" y="2242px"><tspan> Dev-dependencies are not used when compiling a package for building, but are used for</tspan>
<tspan x="10px" y="2242px"><tspan> </tspan><tspan class="fg-cyan bold">--dev</tspan>
</tspan>
<tspan x="10px" y="2260px"><tspan> compiling tests, examples, and benchmarks.</tspan>
<tspan x="10px" y="2260px"><tspan> Add as development dependency</tspan>
</tspan>
<tspan x="10px" y="2278px"><tspan> </tspan>
</tspan>
<tspan x="10px" y="2296px"><tspan> These dependencies are not propagated to other packages which depend on this package.</tspan>
<tspan x="10px" y="2296px"><tspan> Dev-dependencies are not used when compiling a package for building, but are used for</tspan>
</tspan>
<tspan x="10px" y="2314px">
<tspan x="10px" y="2314px"><tspan> compiling tests, examples, and benchmarks.</tspan>
</tspan>
<tspan x="10px" y="2332px"><tspan> </tspan><tspan class="fg-cyan bold">--build</tspan>
<tspan x="10px" y="2332px"><tspan> </tspan>
</tspan>
<tspan x="10px" y="2350px"><tspan> Add as build dependency</tspan>
<tspan x="10px" y="2350px"><tspan> These dependencies are not propagated to other packages which depend on this package.</tspan>
</tspan>
<tspan x="10px" y="2368px"><tspan> </tspan>
<tspan x="10px" y="2368px">
</tspan>
<tspan x="10px" y="2386px"><tspan> Build-dependencies are the only dependencies available for use by build scripts</tspan>
<tspan x="10px" y="2386px"><tspan> </tspan><tspan class="fg-cyan bold">--build</tspan>
</tspan>
<tspan x="10px" y="2404px"><tspan> (`build.rs` files).</tspan>
<tspan x="10px" y="2404px"><tspan> Add as build dependency</tspan>
</tspan>
<tspan x="10px" y="2422px">
<tspan x="10px" y="2422px"><tspan> </tspan>
</tspan>
<tspan x="10px" y="2440px"><tspan> </tspan><tspan class="fg-cyan bold">--target</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;TARGET&gt;</tspan>
<tspan x="10px" y="2440px"><tspan> Build-dependencies are the only dependencies available for use by build scripts</tspan>
</tspan>
<tspan x="10px" y="2458px"><tspan> Add as dependency to the given target platform</tspan>
<tspan x="10px" y="2458px"><tspan> (`build.rs` files).</tspan>
</tspan>
<tspan x="10px" y="2476px">
</tspan>
<tspan x="10px" y="2494px"><tspan>Run `</tspan><tspan class="fg-cyan bold">cargo help add</tspan><tspan class="bold">` for more detailed information.</tspan>
<tspan x="10px" y="2494px"><tspan> </tspan><tspan class="fg-cyan bold">--target</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;TARGET&gt;</tspan>
</tspan>
<tspan x="10px" y="2512px">
<tspan x="10px" y="2512px"><tspan> Add as dependency to the given target platform</tspan>
</tspan>
<tspan x="10px" y="2530px">
</tspan>
<tspan x="10px" y="2548px"><tspan>Run `</tspan><tspan class="fg-cyan bold">cargo help add</tspan><tspan class="bold">` for more detailed information.</tspan>
</tspan>
<tspan x="10px" y="2566px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -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;

View File

@ -0,0 +1,2 @@
[path-bases]
my_base = "."

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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" }

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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"]

View File

@ -0,0 +1,35 @@
<svg width="844px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-cyan { fill: #00AAAA }
.fg-green { fill: #00AA00 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Adding</tspan><tspan> cargo-list-test-fixture-dependency v20.0 to optional dependencies</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> feature `cargo-list-test-fixture-dependency`</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest compatible version</tspan>
</tspan>
<tspan x="10px" y="100px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,2 @@
[path-bases]
my_base = "."

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,8 @@
cargo-features = ["path-bases"]
[workspace]
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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" }

View File

@ -0,0 +1,29 @@
<svg width="740px" height="74px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-green { fill: #00AA00 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Adding</tspan><tspan> cargo-list-test-fixture-dependency (local) to dependencies</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest compatible version</tspan>
</tspan>
<tspan x="10px" y="64px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 907 B

View File

@ -0,0 +1,2 @@
[path-bases]
my_base = "."

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,8 @@
cargo-features = ["path-bases"]
[workspace]
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
[workspace]
[package]
name = "cargo-list-test-fixture-dependency"
version = "0.0.0"
edition = "2015"

View File

@ -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" }

View File

@ -0,0 +1,29 @@
<svg width="740px" height="74px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-green { fill: #00AA00 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Adding</tspan><tspan> cargo-list-test-fixture-dependency (local) to dependencies</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest compatible version</tspan>
</tspan>
<tspan x="10px" y="64px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 907 B

View File

@ -0,0 +1,6 @@
cargo-features = ["path-bases"]
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
cargo-features = ["path-bases"]
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,27 @@
<svg width="740px" height="56px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> path base `bad_base` is undefined. You must add an entry for `bad_base` in the Cargo configuration [path-bases] table.</tspan>
</tspan>
<tspan x="10px" y="46px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 843 B

View File

@ -0,0 +1,4 @@
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -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);
}

View File

@ -0,0 +1,4 @@
[package]
name = "cargo-list-test-fixture"
version = "0.0.0"
edition = "2015"

View File

@ -0,0 +1,37 @@
<svg width="740px" height="56px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> feature `path-bases` is required</tspan>
</tspan>
<tspan x="10px" y="46px">
</tspan>
<tspan x="10px" y="64px"><tspan>The package requires the Cargo feature called `path-bases`, but that feature is not stabilized in this version of Cargo ([..]).</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan>Consider trying a newer version of Cargo (this may require the nightly release).</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#path-bases for more information about the status of this feature.</tspan>
</tspan>
<tspan x="10px" y="118px">
</tspan>
<tspan x="10px" y="136px">
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB