Skip to content

Commit 718b68b

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 2f15e64 commit 718b68b

File tree

69 files changed

+1008
-110
lines changed

Some content is hidden

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

69 files changed

+1008
-110
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/bin/cargo/commands/remove.rs

+44-13
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,37 @@ fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> {
167167

168168
let members = workspace
169169
.members()
170-
.map(|p| LocalManifest::try_new(p.manifest_path()))
170+
.map(|p| {
171+
Ok((
172+
LocalManifest::try_new(p.manifest_path())?,
173+
p.manifest().unstable_features(),
174+
))
175+
})
171176
.collect::<CargoResult<Vec<_>>>()?;
172177

173178
let mut dependencies = members
174-
.iter()
175-
.flat_map(|manifest| {
176-
manifest.get_sections().into_iter().flat_map(|(_, table)| {
177-
table
178-
.as_table_like()
179-
.unwrap()
180-
.iter()
181-
.map(|(key, item)| Dependency::from_toml(&manifest.path, key, item))
182-
.collect::<Vec<_>>()
183-
})
179+
.into_iter()
180+
.flat_map(|(manifest, unstable_features)| {
181+
manifest
182+
.get_sections()
183+
.into_iter()
184+
.flat_map(move |(_, table)| {
185+
table
186+
.as_table_like()
187+
.unwrap()
188+
.iter()
189+
.map(|(key, item)| {
190+
Dependency::from_toml(
191+
workspace.gctx(),
192+
workspace.root(),
193+
&manifest.path,
194+
&unstable_features,
195+
key,
196+
item,
197+
)
198+
})
199+
.collect::<Vec<_>>()
200+
})
184201
})
185202
.collect::<CargoResult<Vec<_>>>()?;
186203

@@ -192,7 +209,14 @@ fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> {
192209
{
193210
deps_table.set_implicit(true);
194211
for (key, item) in deps_table.iter_mut() {
195-
let ws_dep = Dependency::from_toml(&workspace.root(), key.get(), item)?;
212+
let ws_dep = Dependency::from_toml(
213+
workspace.gctx(),
214+
workspace.root(),
215+
&workspace.root(),
216+
workspace.unstable_features(),
217+
key.get(),
218+
item,
219+
)?;
196220

197221
// search for uses of this workspace dependency
198222
let mut is_used = false;
@@ -329,7 +353,14 @@ fn gc_unused_patches(workspace: &Workspace<'_>, resolve: &Resolve) -> CargoResul
329353
patch_table.set_implicit(true);
330354

331355
for (key, item) in patch_table.iter_mut() {
332-
let dep = Dependency::from_toml(&workspace.root_manifest(), key.get(), item)?;
356+
let dep = Dependency::from_toml(
357+
workspace.gctx(),
358+
workspace.root(),
359+
&workspace.root_manifest(),
360+
workspace.unstable_features(),
361+
key.get(),
362+
item,
363+
)?;
333364

334365
// Generate a PackageIdSpec url for querying
335366
let url = if let MaybeWorkspace::Other(source_id) =

src/cargo/ops/cargo_add/mod.rs

+73-12
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;
@@ -20,6 +21,7 @@ use toml_edit::Item as TomlItem;
2021
use crate::core::dependency::DepKind;
2122
use crate::core::registry::PackageRegistry;
2223
use crate::core::FeatureValue;
24+
use crate::core::Features;
2325
use crate::core::Package;
2426
use crate::core::Registry;
2527
use crate::core::Shell;
@@ -28,6 +30,7 @@ use crate::core::Workspace;
2830
use crate::sources::source::QueryKind;
2931
use crate::util::cache_lock::CacheLockMode;
3032
use crate::util::style;
33+
use crate::util::toml::lookup_path_base;
3134
use crate::util::toml_mut::dependency::Dependency;
3235
use crate::util::toml_mut::dependency::GitSource;
3336
use crate::util::toml_mut::dependency::MaybeWorkspace;
@@ -197,7 +200,13 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
197200

198201
print_dep_table_msg(&mut options.gctx.shell(), &dep)?;
199202

200-
manifest.insert_into_table(&dep_table, &dep)?;
203+
manifest.insert_into_table(
204+
&dep_table,
205+
&dep,
206+
workspace.gctx(),
207+
workspace.root(),
208+
options.spec.manifest().unstable_features(),
209+
)?;
201210
if dep.optional == Some(true) {
202211
let is_namespaced_features_supported =
203212
check_rust_version_for_optional_dependency(options.spec.rust_version())?;
@@ -270,8 +279,11 @@ pub struct DepOp {
270279
/// Registry for looking up dependency version
271280
pub registry: Option<String>,
272281

273-
/// Git repo for dependency
282+
/// File system path for dependency
274283
pub path: Option<String>,
284+
/// Specify a named base for a path dependency
285+
pub base: Option<String>,
286+
275287
/// Git repo for dependency
276288
pub git: Option<String>,
277289
/// Specify an alternative git branch
@@ -332,7 +344,19 @@ fn resolve_dependency(
332344
selected
333345
} else if let Some(raw_path) = &arg.path {
334346
let path = paths::normalize_path(&std::env::current_dir()?.join(raw_path));
335-
let src = PathSource::new(&path);
347+
let mut src = PathSource::new(path);
348+
src.base = arg.base.clone();
349+
350+
if let Some(base) = &arg.base {
351+
// Validate that the base is valid.
352+
let workspace_root = || Ok(ws.root_manifest().parent().unwrap());
353+
lookup_path_base(
354+
&PathBaseName::new(base.clone())?,
355+
&gctx,
356+
&workspace_root,
357+
spec.manifest().unstable_features(),
358+
)?;
359+
}
336360

337361
let selected = if let Some(crate_spec) = &crate_spec {
338362
if let Some(v) = crate_spec.version_req() {
@@ -349,9 +373,13 @@ fn resolve_dependency(
349373
}
350374
selected
351375
} else {
352-
let mut source = crate::sources::PathSource::new(&path, src.source_id()?, gctx);
376+
let mut source = crate::sources::PathSource::new(&src.path, src.source_id()?, gctx);
353377
let package = source.root_package()?;
354-
Dependency::from(package.summary())
378+
let mut selected = Dependency::from(package.summary());
379+
if let Some(Source::Path(selected_src)) = &mut selected.source {
380+
selected_src.base = src.base;
381+
}
382+
selected
355383
};
356384
selected
357385
} else if let Some(crate_spec) = &crate_spec {
@@ -361,9 +389,16 @@ fn resolve_dependency(
361389
};
362390
selected_dep = populate_dependency(selected_dep, arg);
363391

364-
let lookup = |dep_key: &_| get_existing_dependency(manifest, dep_key, section);
392+
let lookup = |dep_key: &_| {
393+
get_existing_dependency(
394+
ws,
395+
spec.manifest().unstable_features(),
396+
manifest,
397+
dep_key,
398+
section,
399+
)
400+
};
365401
let old_dep = fuzzy_lookup(&mut selected_dep, lookup, gctx)?;
366-
367402
let mut dependency = if let Some(mut old_dep) = old_dep.clone() {
368403
if old_dep.name != selected_dep.name {
369404
// Assuming most existing keys are not relevant when the package changes
@@ -385,7 +420,9 @@ fn resolve_dependency(
385420
if dependency.source().is_none() {
386421
// Checking for a workspace dependency happens first since a member could be specified
387422
// in the workspace dependencies table as a dependency
388-
let lookup = |toml_key: &_| Ok(find_workspace_dep(toml_key, ws.root_manifest()).ok());
423+
let lookup = |toml_key: &_| {
424+
Ok(find_workspace_dep(toml_key, ws, ws.root_manifest(), ws.unstable_features()).ok())
425+
};
389426
if let Some(_dep) = fuzzy_lookup(&mut dependency, lookup, gctx)? {
390427
dependency = dependency.set_source(WorkspaceSource::new());
391428
} else if let Some(package) = ws.members().find(|p| p.name().as_str() == dependency.name) {
@@ -432,7 +469,12 @@ fn resolve_dependency(
432469
let query = dependency.query(gctx)?;
433470
let query = match query {
434471
MaybeWorkspace::Workspace(_workspace) => {
435-
let dep = find_workspace_dep(dependency.toml_key(), ws.root_manifest())?;
472+
let dep = find_workspace_dep(
473+
dependency.toml_key(),
474+
ws,
475+
ws.root_manifest(),
476+
ws.unstable_features(),
477+
)?;
436478
if let Some(features) = dep.features.clone() {
437479
dependency = dependency.set_inherited_features(features);
438480
}
@@ -547,6 +589,8 @@ fn check_rust_version_for_optional_dependency(
547589
/// If it doesn't exist but exists in another table, let's use that as most likely users
548590
/// want to use the same version across all tables unless they are renaming.
549591
fn get_existing_dependency(
592+
ws: &Workspace<'_>,
593+
unstable_features: &Features,
550594
manifest: &LocalManifest,
551595
dep_key: &str,
552596
section: &DepTable,
@@ -561,7 +605,7 @@ fn get_existing_dependency(
561605
}
562606

563607
let mut possible: Vec<_> = manifest
564-
.get_dependency_versions(dep_key)
608+
.get_dependency_versions(dep_key, ws, unstable_features)
565609
.map(|(path, dep)| {
566610
let key = if path == *section {
567611
(Key::Existing, true)
@@ -776,6 +820,11 @@ fn select_package(
776820
if let Some(reg_name) = dependency.registry.as_deref() {
777821
dep = dep.set_registry(reg_name);
778822
}
823+
if let Some(Source::Path(PathSource { base, .. })) = dependency.source() {
824+
if let Some(Source::Path(dep_src)) = &mut dep.source {
825+
dep_src.base = base.clone();
826+
}
827+
}
779828
Ok(dep)
780829
}
781830
_ => {
@@ -1107,7 +1156,12 @@ fn format_features_version_suffix(dep: &DependencyUI) -> String {
11071156
}
11081157
}
11091158

1110-
fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult<Dependency> {
1159+
fn find_workspace_dep(
1160+
toml_key: &str,
1161+
ws: &Workspace<'_>,
1162+
root_manifest: &Path,
1163+
unstable_features: &Features,
1164+
) -> CargoResult<Dependency> {
11111165
let manifest = LocalManifest::try_new(root_manifest)?;
11121166
let manifest = manifest
11131167
.data
@@ -1127,7 +1181,14 @@ fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult<Depen
11271181
let dep_item = dependencies
11281182
.get(toml_key)
11291183
.with_context(|| format!("could not find {toml_key} in `workspace.dependencies`"))?;
1130-
Dependency::from_toml(root_manifest.parent().unwrap(), toml_key, dep_item)
1184+
Dependency::from_toml(
1185+
ws.gctx(),
1186+
ws.root(),
1187+
root_manifest.parent().unwrap(),
1188+
unstable_features,
1189+
toml_key,
1190+
dep_item,
1191+
)
11311192
}
11321193

11331194
/// Convert a `semver::VersionReq` into a rendered `semver::Version` if all fields are fully

src/cargo/ops/cargo_update.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,16 @@ pub fn write_manifest_upgrades(
398398

399399
let mut any_file_has_changed = false;
400400

401-
let manifest_paths = std::iter::once(ws.root_manifest())
402-
.chain(ws.members().map(|member| member.manifest_path()))
401+
let items = std::iter::once((ws.root_manifest(), ws.unstable_features()))
402+
.chain(ws.members().map(|member| {
403+
(
404+
member.manifest_path(),
405+
member.manifest().unstable_features(),
406+
)
407+
}))
403408
.collect::<Vec<_>>();
404409

405-
for manifest_path in manifest_paths {
410+
for (manifest_path, unstable_features) in items {
406411
trace!("updating TOML manifest at `{manifest_path:?}` with upgraded dependencies");
407412

408413
let crate_root = manifest_path
@@ -417,7 +422,10 @@ pub fn write_manifest_upgrades(
417422
for (mut dep_key, dep_item) in dep_table.iter_mut() {
418423
let dep_key_str = dep_key.get();
419424
let dependency = crate::util::toml_mut::dependency::Dependency::from_toml(
425+
ws.gctx(),
426+
ws.root(),
420427
&manifest_path,
428+
unstable_features,
421429
dep_key_str,
422430
dep_item,
423431
)?;
@@ -472,7 +480,14 @@ pub fn write_manifest_upgrades(
472480
dep.source = Some(Source::Registry(source));
473481

474482
trace!("upgrading dependency {name}");
475-
dep.update_toml(&crate_root, &mut dep_key, dep_item);
483+
dep.update_toml(
484+
ws.gctx(),
485+
ws.root(),
486+
&crate_root,
487+
unstable_features,
488+
&mut dep_key,
489+
dep_item,
490+
)?;
476491
manifest_has_changed = true;
477492
any_file_has_changed = true;
478493
}

0 commit comments

Comments
 (0)