Skip to content

Commit df56212

Browse files
committed
Implement path-bases (RFC 3529) 2/n: cargo add support
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.
1 parent d46eab0 commit df56212

File tree

46 files changed

+566
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+566
-52
lines changed

src/bin/cargo/commands/add.rs

+8
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ Example uses:
101101
.help("Filesystem path to local crate to add")
102102
.group("selected")
103103
.conflicts_with("git"),
104+
clap::Arg::new("base")
105+
.long("base")
106+
.action(ArgAction::Set)
107+
.value_name("BASE")
108+
.help("The path base to use when adding from a local crate (unstable).")
109+
.requires("path"),
104110
clap::Arg::new("git")
105111
.long("git")
106112
.action(ArgAction::Set)
@@ -224,6 +230,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
224230

225231
fn parse_dependencies(gctx: &GlobalContext, matches: &ArgMatches) -> CargoResult<Vec<DepOp>> {
226232
let path = matches.get_one::<String>("path");
233+
let base = matches.get_one::<String>("base");
227234
let git = matches.get_one::<String>("git");
228235
let branch = matches.get_one::<String>("branch");
229236
let rev = matches.get_one::<String>("rev");
@@ -329,6 +336,7 @@ fn parse_dependencies(gctx: &GlobalContext, matches: &ArgMatches) -> CargoResult
329336
public,
330337
registry: registry.clone(),
331338
path: path.map(String::from),
339+
base: base.map(String::from),
332340
git: git.map(String::from),
333341
branch: branch.map(String::from),
334342
rev: rev.map(String::from),

src/cargo/ops/cargo_add/mod.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::str::FromStr;
1212
use anyhow::Context as _;
1313
use cargo_util::paths;
1414
use cargo_util_schemas::core::PartialVersion;
15+
use cargo_util_schemas::manifest::PathBaseName;
1516
use cargo_util_schemas::manifest::RustVersion;
1617
use indexmap::IndexSet;
1718
use itertools::Itertools;
@@ -28,6 +29,7 @@ use crate::core::Workspace;
2829
use crate::sources::source::QueryKind;
2930
use crate::util::cache_lock::CacheLockMode;
3031
use crate::util::style;
32+
use crate::util::toml::lookup_path_base;
3133
use crate::util::toml_mut::dependency::Dependency;
3234
use crate::util::toml_mut::dependency::GitSource;
3335
use crate::util::toml_mut::dependency::MaybeWorkspace;
@@ -270,8 +272,11 @@ pub struct DepOp {
270272
/// Registry for looking up dependency version
271273
pub registry: Option<String>,
272274

273-
/// Git repo for dependency
275+
/// File system path for dependency
274276
pub path: Option<String>,
277+
/// Specify a named base for a path dependency
278+
pub base: Option<String>,
279+
275280
/// Git repo for dependency
276281
pub git: Option<String>,
277282
/// Specify an alternative git branch
@@ -331,10 +336,22 @@ fn resolve_dependency(
331336
};
332337
selected
333338
} else if let Some(raw_path) = &arg.path {
339+
let base_name_and_value = if let Some(base_name) = &arg.base {
340+
let workspace_root = || Ok(ws.root_manifest().parent().unwrap());
341+
let base_value = lookup_path_base(
342+
&PathBaseName::new(base_name.clone())?,
343+
gctx,
344+
&workspace_root,
345+
spec.manifest().unstable_features(),
346+
)?;
347+
Some((base_name.clone(), base_value))
348+
} else {
349+
None
350+
};
334351
let path = paths::normalize_path(&std::env::current_dir()?.join(raw_path));
335-
let src = PathSource::new(&path);
352+
let src = PathSource::new_with_base(path, base_name_and_value);
336353

337-
let selected = if let Some(crate_spec) = &crate_spec {
354+
if let Some(crate_spec) = &crate_spec {
338355
if let Some(v) = crate_spec.version_req() {
339356
// crate specifier includes a version (e.g. `[email protected]`)
340357
anyhow::bail!("cannot specify a path (`{raw_path}`) with a version (`{v}`).");
@@ -349,11 +366,10 @@ fn resolve_dependency(
349366
}
350367
selected
351368
} else {
352-
let mut source = crate::sources::PathSource::new(&path, src.source_id()?, gctx);
369+
let mut source = crate::sources::PathSource::new(&src.path, src.source_id()?, gctx);
353370
let package = source.root_package()?;
354-
Dependency::from(package.summary())
355-
};
356-
selected
371+
Dependency::from_summary(package.summary(), &src.base_name_and_value)
372+
}
357373
} else if let Some(crate_spec) = &crate_spec {
358374
crate_spec.to_dependency()?
359375
} else {
@@ -733,7 +749,12 @@ fn select_package(
733749
anyhow::bail!("the crate `{dependency}` could not be found at `{source}`")
734750
}
735751
1 => {
736-
let mut dep = Dependency::from(&possibilities[0]);
752+
let base_name_and_value = dependency
753+
.source()
754+
.map(|s| s.as_path().map(|p| &p.base_name_and_value))
755+
.flatten()
756+
.unwrap_or(&None);
757+
let mut dep = Dependency::from_summary(&possibilities[0], base_name_and_value);
737758
if let Some(reg_name) = dependency.registry.as_deref() {
738759
dep = dep.set_registry(reg_name);
739760
}

src/cargo/util/toml_mut/dependency.rs

+48-10
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,15 @@ impl Dependency {
412412
table.insert("version", src.version.as_str().into());
413413
}
414414
Some(Source::Path(src)) => {
415-
let relpath = path_field(crate_root, &src.path);
416415
if let Some(r) = src.version.as_deref() {
417416
table.insert("version", r.into());
418417
}
419-
table.insert("path", relpath.into());
418+
if let Some((base_name, base_value)) = src.base_name_and_value.as_ref() {
419+
table.insert("base", base_name.into());
420+
table.insert("path", path_field(base_value, &src.path).into());
421+
} else {
422+
table.insert("path", path_field(crate_root, &src.path).into());
423+
}
420424
}
421425
Some(Source::Git(src)) => {
422426
table.insert("git", src.git.as_str().into());
@@ -493,13 +497,18 @@ impl Dependency {
493497
Some(Source::Registry(src)) => {
494498
overwrite_value(table, "version", src.version.as_str());
495499

496-
for key in ["path", "git", "branch", "tag", "rev", "workspace"] {
500+
for key in ["path", "git", "branch", "tag", "rev", "workspace", "base"] {
497501
table.remove(key);
498502
}
499503
}
500504
Some(Source::Path(src)) => {
501-
let relpath = path_field(crate_root, &src.path);
502-
overwrite_value(table, "path", relpath);
505+
if let Some((base_name, base_value)) = src.base_name_and_value.as_ref() {
506+
overwrite_value(table, "base", base_name);
507+
overwrite_value(table, "path", path_field(base_value, &src.path));
508+
} else {
509+
table.remove("base");
510+
overwrite_value(table, "path", path_field(crate_root, &src.path));
511+
}
503512
if let Some(r) = src.version.as_deref() {
504513
overwrite_value(table, "version", r);
505514
} else {
@@ -533,7 +542,7 @@ impl Dependency {
533542
table.remove("version");
534543
}
535544

536-
for key in ["path", "workspace"] {
545+
for key in ["path", "workspace", "base"] {
537546
table.remove(key);
538547
}
539548
}
@@ -552,6 +561,7 @@ impl Dependency {
552561
"rev",
553562
"package",
554563
"default-features",
564+
"base",
555565
] {
556566
table.remove(key);
557567
}
@@ -653,10 +663,13 @@ impl std::fmt::Display for Dependency {
653663
}
654664
}
655665

656-
impl<'s> From<&'s Summary> for Dependency {
657-
fn from(other: &'s Summary) -> Self {
666+
impl Dependency {
667+
pub(crate) fn from_summary(
668+
other: &Summary,
669+
base_name_and_value: &Option<(String, PathBuf)>,
670+
) -> Self {
658671
let source: Source = if let Some(path) = other.source_id().local_path() {
659-
PathSource::new(path)
672+
PathSource::new_with_base(path, base_name_and_value.clone())
660673
.set_version(other.version().to_string())
661674
.into()
662675
} else if let Some(git_ref) = other.source_id().git_reference() {
@@ -676,6 +689,12 @@ impl<'s> From<&'s Summary> for Dependency {
676689
}
677690
}
678691

692+
impl<'s> From<&'s Summary> for Dependency {
693+
fn from(other: &'s Summary) -> Self {
694+
Dependency::from_summary(other, &None)
695+
}
696+
}
697+
679698
impl From<Summary> for Dependency {
680699
fn from(other: Summary) -> Self {
681700
(&other).into()
@@ -812,6 +831,8 @@ impl std::fmt::Display for RegistrySource {
812831
pub struct PathSource {
813832
/// Local, absolute path.
814833
pub path: PathBuf,
834+
/// If using a named base, the base and relative path.
835+
pub base_name_and_value: Option<(String, PathBuf)>,
815836
/// Version requirement for when published.
816837
pub version: Option<String>,
817838
}
@@ -821,6 +842,19 @@ impl PathSource {
821842
pub fn new(path: impl Into<PathBuf>) -> Self {
822843
Self {
823844
path: path.into(),
845+
base_name_and_value: None,
846+
version: None,
847+
}
848+
}
849+
850+
/// Specify dependency from a path and an optional base.
851+
pub fn new_with_base(
852+
path: impl Into<PathBuf>,
853+
base_name_and_value: Option<(String, PathBuf)>,
854+
) -> Self {
855+
Self {
856+
path: path.into(),
857+
base_name_and_value,
824858
version: None,
825859
}
826860
}
@@ -843,7 +877,11 @@ impl PathSource {
843877

844878
impl std::fmt::Display for PathSource {
845879
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
846-
self.path.display().fmt(f)
880+
if let Some((base_name, _)) = &self.base_name_and_value {
881+
write!(f, "{{{base_name}}}/{}", self.path.display())
882+
} else {
883+
self.path.display().fmt(f)
884+
}
847885
}
848886
}
849887

src/doc/man/cargo-add.md

+6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ Specific commit to use when adding from git.
6363
[Filesystem path](../reference/specifying-dependencies.html#specifying-path-dependencies) to local crate to add.
6464
{{/option}}
6565

66+
{{#option "`--base` _base_" }}
67+
The [path base](../reference/unstable.html#path-bases) to use when adding a local crate.
68+
69+
[Unstable (nightly-only)](../reference/unstable.html#path-bases)
70+
{{/option}}
71+
6672
{{> options-registry }}
6773

6874
{{/options}}

src/doc/man/generated_txt/cargo-add.txt

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ OPTIONS
5656
<https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies>
5757
to local crate to add.
5858

59+
--base base
60+
The path base
61+
<https://doc.rust-lang.org/cargo/reference/unstable.html#path-bases>
62+
to use when adding a local crate.
63+
64+
Unstable (nightly-only)
65+
<https://doc.rust-lang.org/cargo/reference/unstable.html#path-bases>
66+
5967
--registry registry
6068
Name of the registry to use. Registry names are defined in Cargo
6169
config files

src/doc/src/commands/cargo-add.md

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ dependency will be listed in the command's output.
5959
<dd class="option-desc"><a href="../reference/specifying-dependencies.html#specifying-path-dependencies">Filesystem path</a> to local crate to add.</dd>
6060

6161

62+
<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>
63+
<dd class="option-desc">The <a href="../reference/unstable.html#path-bases">path base</a> to use when adding a local crate.</p>
64+
<p><a href="../reference/unstable.html#path-bases">Unstable (nightly-only)</a></dd>
65+
66+
6267
<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>
6368
<dd class="option-desc">Name of the registry to use. Registry names are defined in <a href="../reference/config.html">Cargo config
6469
files</a>. If not specified, the default registry is used,

src/etc/man/cargo-add.1

+7
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ Specific commit to use when adding from git.
7474
\fIFilesystem path\fR <https://doc.rust\-lang.org/cargo/reference/specifying\-dependencies.html#specifying\-path\-dependencies> to local crate to add.
7575
.RE
7676
.sp
77+
\fB\-\-base\fR \fIbase\fR
78+
.RS 4
79+
The \fIpath base\fR <https://doc.rust\-lang.org/cargo/reference/unstable.html#path\-bases> to use when adding a local crate.
80+
.sp
81+
\fIUnstable (nightly\-only)\fR <https://doc.rust\-lang.org/cargo/reference/unstable.html#path\-bases>
82+
.RE
83+
.sp
7784
\fB\-\-registry\fR \fIregistry\fR
7885
.RS 4
7986
Name of the registry to use. Registry names are defined in \fICargo config

0 commit comments

Comments
 (0)