diff --git a/crates/cargo-util-schemas/src/manifest/mod.rs b/crates/cargo-util-schemas/src/manifest/mod.rs index df0bb51dcfd..60741f0ff16 100644 --- a/crates/cargo-util-schemas/src/manifest/mod.rs +++ b/crates/cargo-util-schemas/src/manifest/mod.rs @@ -776,6 +776,7 @@ pub struct TomlDetailedDependency { // `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to // that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file. pub path: Option

, + pub base: Option, pub git: Option, pub branch: Option, pub tag: Option, @@ -815,6 +816,7 @@ impl Default for TomlDetailedDependency

{ registry: Default::default(), registry_index: Default::default(), path: Default::default(), + base: Default::default(), git: Default::default(), branch: Default::default(), tag: Default::default(), diff --git a/src/bin/cargo/commands/add.rs b/src/bin/cargo/commands/add.rs index 30956b00479..f7f59413d0a 100644 --- a/src/bin/cargo/commands/add.rs +++ b/src/bin/cargo/commands/add.rs @@ -100,6 +100,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.") + .requires("path"), clap::Arg::new("git") .long("git") .action(ArgAction::Set) @@ -223,6 +229,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"); @@ -328,6 +335,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/cargo/core/features.rs b/src/cargo/core/features.rs index c44b8d51eb4..66eaa501bae 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -776,6 +776,7 @@ unstable_cli_options!( no_index_update: bool = ("Do not update the registry index even if the cache is outdated"), package_workspace: bool = ("Handle intra-workspace dependencies when packaging"), panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"), + path_bases: bool = ("Allow paths that resolve relatively to a base specified in the config"), profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"), public_dependency: bool = ("Respect a dependency's `public` field in Cargo.toml to control public/private dependencies"), publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"), @@ -1280,6 +1281,7 @@ impl CliUnstable { "package-workspace" => self.package_workspace= parse_empty(k, v)?, "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?, "public-dependency" => self.public_dependency = parse_empty(k, v)?, + "path-bases" => self.path_bases = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, "trim-paths" => self.trim_paths = parse_empty(k, v)?, "publish-timeout" => self.publish_timeout = parse_empty(k, v)?, diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index 98757f595ad..d64f1a0833d 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -28,6 +28,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; @@ -270,8 +271,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 @@ -331,10 +335,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 (path, base_name_and_value) = if let Some(base_name) = &arg.base { + let base_value = lookup_path_base(base_name, gctx, manifest.path.parent().unwrap())?; + ( + base_value.join(raw_path), + Some((base_name.clone(), base_value)), + ) + } else { + (std::env::current_dir()?.join(raw_path), None) + }; + let path = paths::normalize_path(&path); + let src = PathSource::new(path); - let selected = if let Some(crate_spec) = &crate_spec { + let mut selected = if let Some(crate_spec) = &crate_spec { if let Some(v) = crate_spec.version_req() { // crate specifier includes a version (e.g. `docopt@0.8`) anyhow::bail!("cannot specify a path (`{raw_path}`) with a version (`{v}`)."); @@ -349,10 +362,15 @@ 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()) }; + if let Some(selected_source) = selected.source.as_mut() { + if let Source::Path(selected_source) = selected_source { + selected_source.base_name_and_value = base_name_and_value; + } + } selected } else if let Some(crate_spec) = &crate_spec { crate_spec.to_dependency()? diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 4159da35275..436fb22fdac 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Debug, Formatter}; use std::fs; @@ -14,7 +15,7 @@ use crate::sources::IndexSummary; use crate::util::errors::CargoResult; use crate::util::important_paths::find_project_manifest_exact; use crate::util::internal; -use crate::util::toml::read_manifest; +use crate::util::toml::{lookup_path_base, read_manifest}; use crate::util::GlobalContext; use anyhow::Context as _; use cargo_util::paths; @@ -878,7 +879,7 @@ fn read_packages( } } -fn nested_paths(manifest: &Manifest) -> Vec { +fn nested_paths(manifest: &Manifest) -> Vec<(PathBuf, Option)> { let mut nested_paths = Vec::new(); let normalized = manifest.normalized_toml(); let dependencies = normalized @@ -910,7 +911,7 @@ fn nested_paths(manifest: &Manifest) -> Vec { let Some(path) = dep.path.as_ref() else { continue; }; - nested_paths.push(PathBuf::from(path.as_str())); + nested_paths.push((PathBuf::from(path.as_str()), dep.base.clone())); } } nested_paths @@ -1000,8 +1001,36 @@ fn read_nested_packages( // // TODO: filesystem/symlink implications? if !source_id.is_registry() { - for p in nested.iter() { - let path = paths::normalize_path(&path.join(p)); + let mut manifest_gctx = None; + + for (p, base) in nested.iter() { + let p = if let Some(base) = base { + // If the dependency has a path base, then load the global context for the current + // manifest and use it to resolve the path base. + let manifest_gctx = match manifest_gctx { + Some(ref gctx) => gctx, + None => { + let mut new_manifest_gctx = match GlobalContext::default() { + Ok(gctx) => gctx, + Err(err) => return Err(err), + }; + if let Err(err) = new_manifest_gctx.reload_rooted_at(&manifest_path) { + return Err(err); + } + manifest_gctx.insert(new_manifest_gctx) + } + }; + match lookup_path_base(base, manifest_gctx, manifest_path.parent().unwrap()) { + Ok(base) => Cow::Owned(base.join(p)), + Err(err) => { + errors.push(err); + continue; + } + } + } else { + Cow::Borrowed(p) + }; + let path = paths::normalize_path(&path.join(p.as_path())); let result = read_nested_packages(&path, all_packages, source_id, gctx, visited, errors); // Ignore broken manifests found on git repositories. @@ -1019,6 +1048,7 @@ fn read_nested_packages( ); errors.push(err); } else { + trace!("Failed to manifest: {:?}", err); return Err(err); } } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 35318991789..5827520b407 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -901,13 +901,17 @@ impl InheritableFields { }; let mut dep = dep.clone(); if let manifest::TomlDependency::Detailed(detailed) = &mut dep { - if let Some(rel_path) = &detailed.path { - detailed.path = Some(resolve_relative_path( - name, - self.ws_root(), - package_root, - rel_path, - )?); + if detailed.base.is_none() { + // If this is a path dependency without a base, then update the path to be relative + // to the workspace root instead. + if let Some(rel_path) = &detailed.path { + detailed.path = Some(resolve_relative_path( + name, + self.ws_root(), + package_root, + rel_path, + )?); + } } } Ok(dep) @@ -2135,7 +2139,20 @@ fn to_dependency_source_id( // always end up hashing to the same value no matter where it's // built from. if manifest_ctx.source_id.is_path() { - let path = manifest_ctx.root.join(path); + let path = if let Some(base) = orig.base.as_ref() { + if !manifest_ctx.gctx.cli_unstable().path_bases { + bail!("usage of path bases requires `-Z path-bases`"); + } + + lookup_path_base(&base, manifest_ctx.gctx, manifest_ctx.root) + .with_context(|| { + format!("resolving path base for dependency ({name_in_toml})") + })? + .join(path) + } else { + // This is a standard path with no prefix. + manifest_ctx.root.join(path) + }; let path = paths::normalize_path(&path); SourceId::for_path(&path) } else { @@ -2151,6 +2168,50 @@ fn to_dependency_source_id( } } +pub(crate) fn lookup_path_base( + base: &str, + gctx: &GlobalContext, + manifest_root: &Path, +) -> CargoResult { + // Validate the path base name. + if base.is_empty() + || !base.chars().next().unwrap().is_alphabetic() + || base + .chars() + .skip(1) + .any(|c| !c.is_alphanumeric() && c != '_' && c != '-') + { + bail!( + "invalid path base name `{base}`. \ + Path base names must start with a letter and contain only letters, numbers, hyphens, and underscores." + ); + } + + // Look up the relevant base in the Config and use that as the root. + if let Some(path_bases) = + gctx.get::>(&format!("path-bases.{base}"))? + { + Ok(path_bases.resolve_path(gctx)) + } else { + // Otherwise, check the built-in bases. + match base { + "workspace" => { + if let Some(workspace_root) = find_workspace_root(manifest_root, gctx)? { + Ok(workspace_root.parent().unwrap().to_path_buf()) + } else { + bail!( + "the `workspace` built-in path base cannot be used outside of a workspace." + ) + } + } + _ => bail!( + "path base `{base}` is undefined. \ + You must add an entry for `{base}` in the Cargo configuration [path-bases] table." + ), + } + } +} + pub trait ResolveToPath { fn resolve(&self, gctx: &GlobalContext) -> PathBuf; } @@ -2865,6 +2926,7 @@ fn prepare_toml_for_publish( let mut d = d.clone(); // Path dependencies become crates.io deps. d.path.take(); + d.base.take(); // Same with git dependencies. d.git.take(); d.branch.take(); diff --git a/src/cargo/util/toml_mut/dependency.rs b/src/cargo/util/toml_mut/dependency.rs index ce7e6229021..7ae5d238f85 100644 --- a/src/cargo/util/toml_mut/dependency.rs +++ b/src/cargo/util/toml_mut/dependency.rs @@ -412,10 +412,18 @@ impl Dependency { table.insert("version", src.version.as_str().into()); } Some(Source::Path(src)) => { - let relpath = path_field(crate_root, &src.path); if let Some(r) = src.version.as_deref() { table.insert("version", r.into()); } + let relative_to = if let Some((base_name, base_value)) = + src.base_name_and_value.as_ref() + { + table.insert("base", base_name.into()); + base_value + } else { + crate_root + }; + let relpath = path_field(relative_to, &src.path); table.insert("path", relpath.into()); } Some(Source::Git(src)) => { @@ -493,12 +501,20 @@ 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); + let relative_to = + if let Some((base_name, base_value)) = src.base_name_and_value.as_ref() { + overwrite_value(table, "base", base_name); + base_value + } else { + table.remove("base"); + crate_root + }; + let relpath = path_field(relative_to, &src.path); overwrite_value(table, "path", relpath); if let Some(r) = src.version.as_deref() { overwrite_value(table, "version", r); @@ -533,7 +549,7 @@ impl Dependency { table.remove("version"); } - for key in ["path", "workspace"] { + for key in ["path", "workspace", "base"] { table.remove(key); } } @@ -552,6 +568,7 @@ impl Dependency { "rev", "package", "default-features", + "base", ] { table.remove(key); } @@ -812,6 +829,8 @@ impl std::fmt::Display for RegistrySource { pub struct PathSource { /// Local, absolute path. pub path: PathBuf, + /// If using a named base, the base and relative path. + pub base_name_and_value: Option<(String, PathBuf)>, /// Version requirement for when published. pub version: Option, } @@ -821,6 +840,7 @@ impl PathSource { pub fn new(path: impl Into) -> Self { Self { path: path.into(), + base_name_and_value: None, version: None, } } @@ -843,7 +863,11 @@ impl PathSource { impl std::fmt::Display for PathSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.path.display().fmt(f) + if let Some((base_name, _)) = &self.base_name_and_value { + write!(f, "{} (@{base_name})", self.path.display()) + } else { + self.path.display().fmt(f) + } } } diff --git a/src/doc/man/cargo-add.md b/src/doc/man/cargo-add.md index 6d388cb5417..9b5a8bbc61e 100644 --- a/src/doc/man/cargo-add.md +++ b/src/doc/man/cargo-add.md @@ -10,7 +10,7 @@ cargo-add --- Add dependencies to a Cargo.toml manifest file ## SYNOPSIS `cargo add` [_options_] _crate_...\ -`cargo add` [_options_] `--path` _path_\ +`cargo add` [_options_] `--path` _path_ [`--base` _base_]\ `cargo add` [_options_] `--git` _url_ [_crate_...] @@ -63,6 +63,10 @@ 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/specifying-dependencies.html#path-bases) to use when adding a local crate. +{{/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 b4f006b9e17..9e942a96de6 100644 --- a/src/doc/man/generated_txt/cargo-add.txt +++ b/src/doc/man/generated_txt/cargo-add.txt @@ -5,7 +5,7 @@ NAME SYNOPSIS cargo add [options] crate… - cargo add [options] --path path + cargo add [options] --path path [--base base] cargo add [options] --git url [crate…] DESCRIPTION @@ -56,6 +56,11 @@ OPTIONS to local crate to add. + --base base + The path base + + to use when adding a local crate. + --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 0411bdd5c30..362d37b6c59 100644 --- a/src/doc/src/commands/cargo-add.md +++ b/src/doc/src/commands/cargo-add.md @@ -6,7 +6,7 @@ cargo-add --- Add dependencies to a Cargo.toml manifest file ## SYNOPSIS `cargo add` [_options_] _crate_...\ -`cargo add` [_options_] `--path` _path_\ +`cargo add` [_options_] `--path` _path_ [`--base` _base_]\ `cargo add` [_options_] `--git` _url_ [_crate_...] @@ -59,6 +59,10 @@ 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.
+ +
--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/doc/src/reference/config.md b/src/doc/src/reference/config.md index 965642cafc5..7629bb57c76 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -195,6 +195,11 @@ hyperlinks = true # whether cargo inserts links into output unicode = true # whether cargo can render output using non-ASCII unicode characters progress.when = 'auto' # whether cargo shows progress bar progress.width = 80 # width of progress bar + +[path-bases] +# Named base directories that can be used in path dependencies. +PATH_BASE_1 = "/path/to/somewhere" +PATH_BASE_2 = "another/path" ``` ## Environment variables @@ -1358,3 +1363,14 @@ Sets the width for progress bar. [crates.io]: https://crates.io/ [target triple]: ../appendix/glossary.md#target '"target" (glossary)' [``]: ../appendix/glossary.md#target '"target" (glossary)' + +### `[path-bases]` + +* Type: string +* Default: see below +* Environment: `CARGO_PATH_BASES_` + +The `[path-bases]` table defines a set of path prefixes that can be used to +prepend the locations of `path` dependencies. See the +[specifying dependencies](specifying-dependencies.md#path-bases) +documentation for more information. diff --git a/src/doc/src/reference/specifying-dependencies.md b/src/doc/src/reference/specifying-dependencies.md index 9ef98e22a01..cfe0ddc6941 100644 --- a/src/doc/src/reference/specifying-dependencies.md +++ b/src/doc/src/reference/specifying-dependencies.md @@ -346,6 +346,56 @@ The use of `path` and `version` keys together is explained in the [Multiple loca > See the [Multiple locations](#multiple-locations) section > for a fallback alternative for `git` and `path` dependencies. +### Path Bases + +A `path` dependency may optionally specify a base by setting the `base` key to +the name of a path base from the `[path-bases]` table in either the +[configuration](config.md) or one of the [built-in path bases](#built-in-path-bases). +The value of that path base is prepended to the `path` value (along with a path +separator if necessary) to produce the actual location where Cargo will look for +the dependency. + +For example, if the `Cargo.toml` contains: + +```toml +[dependencies] +foo = { path = "foo", base = "dev" } +``` + +Given a `[path-bases]` table in the configuration that contains: + +```toml +[path-bases] +dev = "/home/user/dev/rust/libraries/" +``` + +This will produce a `path` dependency `foo` located at +`/home/user/dev/rust/libraries/foo`. + +Path bases can be either absolute or relative. Relative path bases are relative +to the parent directory of the configuration file that declared that path base. + +The name of a path base must use only [alphanumeric](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphanumeric) +characters or `-` or `_`, must start with an [alphabetic](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphabetic) +character, and must not be empty. + +If the name of path base used in a dependency is neither in the configuration +nor one of the built-in path base, then Cargo will raise an error. + +#### Built-in path bases + +Cargo provides implicit path bases that can be used without the need to specify +them in a `[path-bases]` table. + +* `workspace` - If a project is [a workspace or workspace member](workspaces.md) +then this path base is defined as the parent directory of the root `Cargo.toml` +of the workspace. + +If a built-in path base name is also declared in the configuration, then Cargo +will prefer the value in the configuration. The allows Cargo to add new built-in +path bases without compatibility issues (as existing uses will shadow the +built-in name). + ## Multiple locations It is possible to specify both a registry version and a `git` or `path` diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 18be45fc2b0..fb10d232e6e 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -101,6 +101,7 @@ Each new feature described below should explain how to use it. * [Edition 2024](#edition-2024) — Adds support for the 2024 Edition. * [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs. * [`[lints.cargo]`](#lintscargo) --- Allows configuring lints for Cargo. + * [path bases](#path-bases) --- Named base directories for path dependencies. * Information and metadata * [Build-plan](#build-plan) --- Emits JSON information on which commands will be run. * [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure. @@ -1570,6 +1571,58 @@ implicit-features = "warn" workspace = true ``` +## Path Bases + +* Tracking Issue: [#14355](https://github.com/rust-lang/cargo/issues/14355) + +A `path` dependency may optionally specify a base by setting the `base` key to +the name of a path base from the `[path-bases]` table in either the +[configuration](config.md) or one of the [built-in path bases](#built-in-path-bases). +The value of that path base is prepended to the `path` value (along with a path +separator if necessary) to produce the actual location where Cargo will look for +the dependency. + +For example, if the `Cargo.toml` contains: + +```toml +[dependencies] +foo = { path = "foo", base = "dev" } +``` + +Given a `[path-bases]` table in the configuration that contains: + +```toml +[path-bases] +dev = "/home/user/dev/rust/libraries/" +``` + +This will produce a `path` dependency `foo` located at +`/home/user/dev/rust/libraries/foo`. + +Path bases can be either absolute or relative. Relative path bases are relative +to the parent directory of the configuration file that declared that path base. + +The name of a path base must use only [alphanumeric](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphanumeric) +characters or `-` or `_`, must start with an [alphabetic](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphabetic) +character, and must not be empty. + +If the name of path base used in a dependency is neither in the configuration +nor one of the built-in path base, then Cargo will raise an error. + +#### Built-in path bases + +Cargo provides implicit path bases that can be used without the need to specify +them in a `[path-bases]` table. + +* `workspace` - If a project is [a workspace or workspace member](workspaces.md) +then this path base is defined as the parent directory of the root `Cargo.toml` +of the workspace. + +If a built-in path base name is also declared in the configuration, then Cargo +will prefer the value in the configuration. The allows Cargo to add new built-in +path bases without compatibility issues (as existing uses will shadow the +built-in name). + # Stabilized and removed features ## Compile progress diff --git a/src/etc/man/cargo-add.1 b/src/etc/man/cargo-add.1 index ed8859da37f..277d98b4580 100644 --- a/src/etc/man/cargo-add.1 +++ b/src/etc/man/cargo-add.1 @@ -8,7 +8,7 @@ cargo\-add \[em] Add dependencies to a Cargo.toml manifest file .SH "SYNOPSIS" \fBcargo add\fR [\fIoptions\fR] \fIcrate\fR\[u2026] .br -\fBcargo add\fR [\fIoptions\fR] \fB\-\-path\fR \fIpath\fR +\fBcargo add\fR [\fIoptions\fR] \fB\-\-path\fR \fIpath\fR [\fB\-\-base\fR \fIbase\fR] .br \fBcargo add\fR [\fIoptions\fR] \fB\-\-git\fR \fIurl\fR [\fIcrate\fR\[u2026]] .SH "DESCRIPTION" @@ -74,6 +74,11 @@ 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. +.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/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index e5386620e46..2549003e518 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -66,33 +66,35 @@ -Z panic-abort-tests Enable support to run tests with -Cpanic=abort - -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file + -Z path-bases Allow paths that resolve relatively to a base specified in the config - -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies + -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file - -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file + -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies - -Z rustdoc-map Allow passing external documentation mappings to rustdoc + -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file - -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies + -Z rustdoc-map Allow passing external documentation mappings to rustdoc - -Z script Enable support for single-file, `.rs` packages + -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies - -Z target-applies-to-host Enable the `target-applies-to-host` key in the .cargo/config.toml file + -Z script Enable support for single-file, `.rs` packages - -Z trim-paths Enable the `trim-paths` option in profiles + -Z target-applies-to-host Enable the `target-applies-to-host` key in the .cargo/config.toml file - -Z unstable-options Allow the usage of unstable options + -Z trim-paths Enable the `trim-paths` option in profiles - + -Z unstable-options Allow the usage of unstable options - Run with `cargo -Z [FLAG] [COMMAND]` + - + Run with `cargo -Z [FLAG] [COMMAND]` - See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags. + - + See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags. + + diff --git a/tests/testsuite/cargo_add/help/stdout.term.svg b/tests/testsuite/cargo_add/help/stdout.term.svg index 2e1cacd322a..56dbd038a36 100644 --- a/tests/testsuite/cargo_add/help/stdout.term.svg +++ b/tests/testsuite/cargo_add/help/stdout.term.svg @@ -213,83 +213,89 @@ - --git <URI> + --base <BASE> - Git repository location + The path base to use when adding from a local crate. - + - 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 62feb8422c8..74156bb9c3a 100644 --- a/tests/testsuite/cargo_add/mod.rs +++ b/tests/testsuite/cargo_add/mod.rs @@ -76,6 +76,7 @@ mod overwrite_default_features; mod overwrite_default_features_with_no_default_features; mod overwrite_features; mod overwrite_git_with_path; +mod overwrite_git_with_path_base; mod overwrite_inherit_features_noop; mod overwrite_inherit_noop; mod overwrite_inherit_optional_noop; @@ -91,6 +92,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; @@ -105,6 +107,9 @@ 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_dev; mod path_inferred_name; mod path_inferred_name_conflicts_full_feature; diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/.cargo/config.toml b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/.cargo/config.toml new file mode 100644 index 00000000000..4539a438423 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/.cargo/config.toml @@ -0,0 +1,2 @@ +[path-bases] +my_base = "." diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/dependency/Cargo.toml b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_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/overwrite_git_with_path_base/in/dependency/src/lib.rs b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/dependency/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/primary/Cargo.toml b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/primary/Cargo.toml new file mode 100644 index 00000000000..49adccdbfbd --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/primary/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { git = "git://git.git", branch = "main", optional = true } diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/primary/src/lib.rs b/tests/testsuite/cargo_add/overwrite_git_with_path_base/in/primary/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/mod.rs b/tests/testsuite/cargo_add/overwrite_git_with_path_base/mod.rs new file mode 100644 index 00000000000..dc29cf38611 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_path_base/mod.rs @@ -0,0 +1,40 @@ +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(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver) + .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("-Zpath-bases") + .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/overwrite_git_with_path_base/out/dependency/Cargo.toml b/tests/testsuite/cargo_add/overwrite_git_with_path_base/out/dependency/Cargo.toml new file mode 100644 index 00000000000..c645a3371c0 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_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/overwrite_git_with_path_base/out/primary/Cargo.toml b/tests/testsuite/cargo_add/overwrite_git_with_path_base/out/primary/Cargo.toml new file mode 100644 index 00000000000..e1250c93d2b --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_path_base/out/primary/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +cargo-list-test-fixture-dependency = { optional = true, base = "my_base", path = "dependency", version = "0.0.0" } + +[features] +cargo-list-test-fixture-dependency = ["dep:cargo-list-test-fixture-dependency"] diff --git a/tests/testsuite/cargo_add/overwrite_git_with_path_base/stderr.term.svg b/tests/testsuite/cargo_add/overwrite_git_with_path_base/stderr.term.svg new file mode 100644 index 00000000000..597efa5a7e2 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_git_with_path_base/stderr.term.svg @@ -0,0 +1,31 @@ + + + + + + + Adding cargo-list-test-fixture-dependency (local) to optional dependencies + + Adding feature `cargo-list-test-fixture-dependency` + + Locking 2 packages to latest compatible versions + + + + + + 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..b92c6e86249 --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/primary/Cargo.toml @@ -0,0 +1,9 @@ +[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..19eecbf2d3e --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/mod.rs @@ -0,0 +1,40 @@ +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(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver) + .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("-Zpath-bases") + .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..ec771442a1d --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/out/primary/Cargo.toml @@ -0,0 +1,12 @@ +[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..d2bab110c2e --- /dev/null +++ b/tests/testsuite/cargo_add/overwrite_path_base_with_version/stderr.term.svg @@ -0,0 +1,37 @@ + + + + + + + Updating `dummy-registry` index + + Adding cargo-list-test-fixture-dependency v20.0 to optional dependencies + + Adding feature `cargo-list-test-fixture-dependency` + + Locking 2 packages to latest compatible versions + + Adding cargo-list-test-fixture-dependency v20.0.0+my-package (latest: v99999.0.0+my-package) + + + + + + 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..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/in/primary/Cargo.toml @@ -0,0 +1,6 @@ +[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..dc29cf38611 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/mod.rs @@ -0,0 +1,40 @@ +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(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver) + .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("-Zpath-bases") + .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..1cca70e201f --- /dev/null +++ b/tests/testsuite/cargo_add/path_base/out/primary/Cargo.toml @@ -0,0 +1,9 @@ +[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..602e208606e --- /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 2 packages to latest compatible versions + + + + + + 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..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/in/primary/Cargo.toml @@ -0,0 +1,6 @@ +[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..ca1645d5e52 --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/mod.rs @@ -0,0 +1,40 @@ +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(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver) + .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("-Zpath-bases") + .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..1cca70e201f --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_inferred_name/out/primary/Cargo.toml @@ -0,0 +1,9 @@ +[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..602e208606e --- /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 2 packages to latest compatible versions + + + + + + 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..8194d1deb0e --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/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_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..41caddc30bd --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/mod.rs @@ -0,0 +1,28 @@ +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.join("primary"); + + snapbox::cmd::Command::cargo_ui() + .arg("-Zpath-bases") + .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..8194d1deb0e --- /dev/null +++ b/tests/testsuite/cargo_add/path_base_missing_base_path/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_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_inferred_name/mod.rs b/tests/testsuite/cargo_add/path_inferred_name/mod.rs index 3729f9946d4..ca77e190e9a 100644 --- a/tests/testsuite/cargo_add/path_inferred_name/mod.rs +++ b/tests/testsuite/cargo_add/path_inferred_name/mod.rs @@ -27,7 +27,7 @@ fn case() { snapbox::cmd::Command::cargo_ui() .arg("add") - .arg_line("cargo-list-test-fixture-dependency --path ../dependency") + .arg_line("--path ../dependency") .current_dir(&cwd) .assert() .success() diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index 21943c3e29c..8dfcdb0407c 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -380,6 +380,107 @@ hello world .run(); } +#[cargo_test] +fn dependency_in_submodule_via_path_base() { + // Using a submodule prevents the dependency from being discovered during the directory walk, + // so Cargo will need to follow the path dependency to discover it. + + let git_project = git::new("dep1", |project| { + project + .file(".cargo/config.toml", "[path-bases]\nsubmodules = 'submods'") + .file( + "Cargo.toml", + r#" + [package] + + name = "dep1" + version = "0.5.0" + edition = "2015" + authors = ["carlhuda@example.com"] + + [dependencies.dep2] + + version = "0.5.0" + path = "dep2" + base = "submodules" + + [lib] + + name = "dep1" + "#, + ) + .file( + "src/dep1.rs", + r#" + extern crate dep2; + + pub fn hello() -> &'static str { + dep2::hello() + } + "#, + ) + }); + + let git_project2 = git::new("dep2", |project| { + project + .file("Cargo.toml", &basic_lib_manifest("dep2")) + .file( + "src/dep2.rs", + r#" + pub fn hello() -> &'static str { + "hello world" + } + "#, + ) + }); + + let repo = git2::Repository::open(&git_project.root()).unwrap(); + let url = git_project2.root().to_url().to_string(); + git::add_submodule(&repo, &url, Path::new("submods/dep2")); + git::commit(&repo); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [dependencies.dep1] + + version = "0.5.0" + git = '{}' + + [[bin]] + + name = "foo" + "#, + git_project.url() + ), + ) + .file( + "src/foo.rs", + &main_file(r#""{}", dep1::hello()"#, &["dep1"]), + ) + .build(); + + p.cargo("build").run(); + + assert!(p.bin("foo").is_file()); + + p.process(&p.bin("foo")) + .with_stdout_data(str![[r#" +hello world + +"#]]) + .run(); +} + #[cargo_test] fn cargo_compile_with_malformed_nested_paths() { let git_project = git::new("dep1", |project| { diff --git a/tests/testsuite/patch.rs b/tests/testsuite/patch.rs index bc9bd535bf4..2aee7b99ca5 100644 --- a/tests/testsuite/patch.rs +++ b/tests/testsuite/patch.rs @@ -3028,3 +3028,45 @@ foo v0.0.0 ([ROOT]/foo) assert_eq!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig")); } + +#[cargo_test] +fn patch_with_base() { + let bar = project() + .at("bar") + .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) + .file("src/lib.rs", "pub fn hello() {}") + .build(); + Package::new("bar", "0.5.0").publish(); + + let p = project() + .file( + ".cargo/config.toml", + &format!( + "[path-bases]\ntest = '{}'", + bar.root().parent().unwrap().display() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + edition = "2018" + + [dependencies] + bar = "0.5.0" + + [patch.crates-io.bar] + path = 'bar' + base = 'test' + "#, + ) + .file("src/lib.rs", "use bar::hello as _;") + .build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} diff --git a/tests/testsuite/path.rs b/tests/testsuite/path.rs index 17179a520cc..736029f71f8 100644 --- a/tests/testsuite/path.rs +++ b/tests/testsuite/path.rs @@ -589,6 +589,388 @@ Caused by: .run(); } +#[cargo_test] +fn path_bases_not_stable() { + let bar = project() + .at("bar") + .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + ".cargo/config.toml", + &format!( + "[path-bases]\ntest = '{}'", + bar.root().parent().unwrap().display() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = 'test' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` + +Caused by: + usage of path bases requires `-Z path-bases` +", + ) + .run(); +} + +#[cargo_test] +fn path_with_base() { + let bar = project() + .at("bar") + .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + ".cargo/config.toml", + &format!( + "[path-bases]\ntest = '{}'", + bar.root().parent().unwrap().display() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = 'test' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} + +#[cargo_test] +fn workspace_with_base() { + let bar = project() + .at("dep_with_base") + .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + ".cargo/config.toml", + &format!( + "[path-bases]\ntest = '{}'", + bar.root().parent().unwrap().display() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + name = "parent" + version = "0.1.0" + authors = [] + + [workspace] + members = ["child"] + + [workspace.dependencies.dep_with_base] + path = 'dep_with_base' + base = 'test' + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "child/Cargo.toml", + r#" + [package] + name = "child" + version = "0.1.0" + authors = [] + workspace = ".." + + [dependencies.dep_with_base] + workspace = true + "#, + ) + .file("child/src/main.rs", "fn main() {}"); + let p = p.build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} + +#[cargo_test] +fn path_with_relative_base() { + project() + .at("shared_proj/bar") + .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + "../.cargo/config.toml", + "[path-bases]\ntest = 'shared_proj'", + ) + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = 'test' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} + +#[cargo_test] +fn workspace_builtin_base() { + project() + .at("dep_with_base") + .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "parent" + version = "0.1.0" + authors = [] + + [workspace] + members = ["child"] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "child/Cargo.toml", + r#" + [package] + name = "child" + version = "0.1.0" + authors = [] + workspace = ".." + + [dependencies.dep_with_base] + path = '../dep_with_base' + base = 'workspace' + "#, + ) + .file("child/src/main.rs", "fn main() {}"); + let p = p.build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} + +#[cargo_test] +fn shadow_workspace_builtin_base() { + let bar = project() + .at("dep_with_base") + .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) + .file("src/lib.rs", "") + .build(); + + let p = project() + .file( + ".cargo/config.toml", + &format!( + "[path-bases]\nworkspace = '{}/subdir'", + bar.root().parent().unwrap().display() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + name = "parent" + version = "0.1.0" + authors = [] + + [workspace] + members = ["child"] + + [workspace.dependencies.dep_with_base] + path = '../dep_with_base' + base = 'workspace' + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "child/Cargo.toml", + r#" + [package] + name = "child" + version = "0.1.0" + authors = [] + workspace = ".." + + [dependencies.dep_with_base] + workspace = true + "#, + ) + .file("child/src/main.rs", "fn main() {}"); + let p = p.build(); + + p.cargo("build -v -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .run(); +} + +#[cargo_test] +fn unknown_base() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = 'test' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` + +Caused by: + resolving path base for dependency (bar) + +Caused by: + path base `test` is undefined. You must add an entry for `test` in the Cargo configuration [path-bases] table. +", + ) + .run(); +} + +#[cargo_test] +fn invalid_base() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = '^^not-valid^^' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` + +Caused by: + resolving path base for dependency (bar) + +Caused by: + invalid path base name `^^not-valid^^`. Path base names must start with a letter and contain only letters, numbers, hyphens, and underscores. +", + ) + .run(); +} + +#[cargo_test] +fn workspace_builtin_base_not_a_workspace() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = 'bar' + base = 'workspace' + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build -Zpath-bases") + .masquerade_as_nightly_cargo(&["path-bases"]) + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` + +Caused by: + resolving path base for dependency (bar) + +Caused by: + the `workspace` built-in path base cannot be used outside of a workspace. +", + ) + .run(); +} + #[cargo_test] fn override_relative() { let bar = project()