Skip to content

Commit

Permalink
Implement path-bases (RFC 3529) 2/n: cargo add support
Browse files Browse the repository at this point in the history
RFC: rust-lang/rfcs#3529
Tracking Issue: #14355

This PR adds the `--base` option to `cargo add` to allow adding a path dependency with a path base.
  • Loading branch information
dpaoliello committed Aug 20, 2024
1 parent 9e152bb commit ffd37c4
Show file tree
Hide file tree
Showing 46 changed files with 559 additions and 45 deletions.
8 changes: 8 additions & 0 deletions src/bin/cargo/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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),
Expand Down
50 changes: 46 additions & 4 deletions src/cargo/ops/cargo_add/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -270,8 +273,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
Expand Down Expand Up @@ -331,10 +337,41 @@ fn resolve_dependency(
};
selected
} else if let Some(raw_path) = &arg.path {
let base_name_and_value = if let Some(base_name) = &arg.base {
let workspace_root = ws.root_manifest().parent().unwrap().to_path_buf();
let workspace_root = || Ok(&workspace_root);

let features = {
let empty = Vec::new();
let mut warnings = Vec::new();
let cargo_features = spec
.manifest()
.original_toml()
.cargo_features
.as_ref()
.unwrap_or(&empty);
let features = Features::new(cargo_features, gctx, &mut warnings, true)?;
if !warnings.is_empty() {
for warning in warnings {
gctx.shell().warn(warning)?;
}
}
features
};
let base_value = lookup_path_base(
&PathBaseName::new(base_name.clone())?,
gctx,
&workspace_root,
&features,
)?;
Some((base_name.clone(), base_value))
} else {
None
};
let path = paths::normalize_path(&std::env::current_dir()?.join(raw_path));
let src = PathSource::new(&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. `[email protected]`)
anyhow::bail!("cannot specify a path (`{raw_path}`) with a version (`{v}`).");
Expand All @@ -349,10 +386,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()?
Expand Down
31 changes: 24 additions & 7 deletions src/cargo/util/toml_mut/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,15 @@ 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());
}
table.insert("path", relpath.into());
if let Some((base_name, base_value)) = src.base_name_and_value.as_ref() {
table.insert("base", base_name.into());
table.insert("path", path_field(base_value, &src.path).into());
} else {
table.insert("path", path_field(crate_root, &src.path).into());
}
}
Some(Source::Git(src)) => {
table.insert("git", src.git.as_str().into());
Expand Down Expand Up @@ -493,13 +497,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);
overwrite_value(table, "path", relpath);
if let Some((base_name, base_value)) = src.base_name_and_value.as_ref() {
overwrite_value(table, "base", base_name);
overwrite_value(table, "path", path_field(base_value, &src.path));
} else {
table.remove("base");
overwrite_value(table, "path", path_field(crate_root, &src.path));
}
if let Some(r) = src.version.as_deref() {
overwrite_value(table, "version", r);
} else {
Expand Down Expand Up @@ -533,7 +542,7 @@ impl Dependency {
table.remove("version");
}

for key in ["path", "workspace"] {
for key in ["path", "workspace", "base"] {
table.remove(key);
}
}
Expand All @@ -552,6 +561,7 @@ impl Dependency {
"rev",
"package",
"default-features",
"base",
] {
table.remove(key);
}
Expand Down Expand Up @@ -812,6 +822,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<String>,
}
Expand All @@ -821,6 +833,7 @@ impl PathSource {
pub fn new(path: impl Into<PathBuf>) -> Self {
Self {
path: path.into(),
base_name_and_value: None,
version: None,
}
}
Expand All @@ -843,7 +856,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)
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/doc/man/cargo-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
8 changes: 8 additions & 0 deletions src/doc/man/generated_txt/cargo-add.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/doc/src/commands/cargo-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions src/etc/man/cargo-add.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 40 additions & 34 deletions tests/testsuite/cargo_add/help/stdout.term.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ffd37c4

Please sign in to comment.