From 7dc8be541460f83c27161b0513d3644f83cef474 Mon Sep 17 00:00:00 2001 From: Ted Kaminski Date: Fri, 9 Sep 2022 19:57:45 +0000 Subject: [PATCH] Ignore `workspace.default-members` when running `cargo install` on root package of a non-virtual workspace --- src/cargo/core/compiler/build_config.rs | 7 ++-- src/cargo/ops/cargo_compile/compile_filter.rs | 2 +- src/cargo/ops/cargo_compile/mod.rs | 2 +- src/cargo/ops/cargo_compile/packages.rs | 2 +- src/cargo/ops/cargo_install.rs | 25 +++++++----- tests/testsuite/install.rs | 40 +++++++++++++++++++ 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index b512c7f5da0..885b124b976 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -6,10 +6,11 @@ use cargo_util::ProcessBuilder; use serde::ser; use std::cell::RefCell; use std::path::PathBuf; +use std::sync::Arc; use std::thread::available_parallelism; /// Configuration information for a rustc build. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BuildConfig { /// The requested kind of compilation for this session pub requested_kinds: Vec, @@ -33,7 +34,7 @@ pub struct BuildConfig { pub primary_unit_rustc: Option, /// A thread used by `cargo fix` to receive messages on a socket regarding /// the success/failure of applying fixes. - pub rustfix_diagnostic_server: RefCell>, + pub rustfix_diagnostic_server: Arc>>, /// The directory to copy final artifacts to. Note that even if `out_dir` is /// set, a copy of artifacts still could be found a `target/(debug\release)` /// as usual. @@ -100,7 +101,7 @@ impl BuildConfig { build_plan: false, unit_graph: false, primary_unit_rustc: None, - rustfix_diagnostic_server: RefCell::new(None), + rustfix_diagnostic_server: Arc::new(RefCell::new(None)), export_dir: None, future_incompat_report: false, timing_outputs: Vec::new(), diff --git a/src/cargo/ops/cargo_compile/compile_filter.rs b/src/cargo/ops/cargo_compile/compile_filter.rs index c5200c92861..d5e326dfe44 100644 --- a/src/cargo/ops/cargo_compile/compile_filter.rs +++ b/src/cargo/ops/cargo_compile/compile_filter.rs @@ -34,7 +34,7 @@ pub enum FilterRule { /// /// [`generate_root_units`]: super::UnitGenerator::generate_root_units /// [`Packages`]: crate::ops::Packages -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum CompileFilter { /// The default set of Cargo targets. Default { diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index 3022390dd6e..a25c8f7c7b9 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -68,7 +68,7 @@ pub use packages::Packages; /// of it as `CompileOptions` are high-level settings requested on the /// command-line, and `BuildConfig` are low-level settings for actually /// driving `rustc`. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CompileOptions { /// Configuration information for a rustc build pub build_config: BuildConfig, diff --git a/src/cargo/ops/cargo_compile/packages.rs b/src/cargo/ops/cargo_compile/packages.rs index 4bc0ff231c2..2d14d60a69c 100644 --- a/src/cargo/ops/cargo_compile/packages.rs +++ b/src/cargo/ops/cargo_compile/packages.rs @@ -13,7 +13,7 @@ use anyhow::{bail, Context as _}; /// /// Generally, it represents the combination of all `-p` flag. When working within /// a workspace, `--exclude` and `--workspace` flags also contribute to it. -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Clone)] pub enum Packages { /// Packages selected by default. Usually means no flag provided. Default, diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 72bcb41c8d5..21de0997bf5 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -5,8 +5,8 @@ use std::{env, fs}; use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput}; use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Workspace}; -use crate::ops::CompileFilter; use crate::ops::{common_for_install_and_uninstall::*, FilterRule}; +use crate::ops::{CompileFilter, Packages}; use crate::sources::{GitSource, PathSource, SourceConfigMap}; use crate::util::errors::CargoResult; use crate::util::{Config, Filesystem, Rustc, ToSemver, VersionReqExt}; @@ -37,7 +37,7 @@ impl Drop for Transaction { struct InstallablePackage<'cfg, 'a> { config: &'cfg Config, - opts: &'a ops::CompileOptions, + opts: ops::CompileOptions, root: Filesystem, source_id: SourceId, vers: Option<&'a str>, @@ -60,7 +60,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { source_id: SourceId, from_cwd: bool, vers: Option<&'a str>, - opts: &'a ops::CompileOptions, + original_opts: &'a ops::CompileOptions, force: bool, no_track: bool, needs_update_if_source_is_index: bool, @@ -145,7 +145,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { dep.clone(), &mut source, config, - opts, + original_opts, &root, &dst, force, @@ -167,7 +167,14 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { } }; - let (ws, rustc, target) = make_ws_rustc_target(config, opts, &source_id, pkg.clone())?; + // When we build this package, we want to build the *specified* package only, + // and avoid building e.g. workspace default-members instead. Do so by constructing + // specialized compile options specific to the identified package. + // See test `path_install_workspace_root_despite_default_members`. + let mut opts = original_opts.clone(); + opts.spec = Packages::Packages(vec![pkg.name().to_string()]); + + let (ws, rustc, target) = make_ws_rustc_target(config, &opts, &source_id, pkg.clone())?; // If we're installing in --locked mode and there's no `Cargo.lock` published // ie. the bin was published before https://github.com/rust-lang/cargo/pull/7026 if config.locked() && !ws.root().join("Cargo.lock").exists() { @@ -235,7 +242,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { // Check for conflicts. ip.no_track_duplicates(&dst)?; } else if is_installed( - &ip.pkg, config, opts, &ip.rustc, &ip.target, &ip.root, &dst, force, + &ip.pkg, config, &ip.opts, &ip.rustc, &ip.target, &ip.root, &dst, force, )? { let msg = format!( "package `{}` is already installed, use --force to override", @@ -297,7 +304,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { self.check_yanked_install()?; let exec: Arc = Arc::new(DefaultExecutor); - let compile = ops::compile_ws(&self.ws, self.opts, &exec).with_context(|| { + let compile = ops::compile_ws(&self.ws, &self.opts, &exec).with_context(|| { if let Some(td) = td_opt.take() { // preserve the temporary directory, so the user can inspect it td.into_path(); @@ -372,7 +379,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { &dst, &self.pkg, self.force, - self.opts, + &self.opts, &self.target, &self.rustc.verbose_version, )?; @@ -439,7 +446,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { &self.pkg, &successful_bins, self.vers.map(|s| s.to_string()), - self.opts, + &self.opts, &self.target, &self.rustc.verbose_version, ); diff --git a/tests/testsuite/install.rs b/tests/testsuite/install.rs index ed4e02f1e7d..cbdd22f06d4 100644 --- a/tests/testsuite/install.rs +++ b/tests/testsuite/install.rs @@ -1292,6 +1292,46 @@ fn use_path_workspace() { assert_eq!(lock, lock2, "different lockfiles"); } +#[cargo_test] +fn path_install_workspace_root_despite_default_members() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "ws-root" + version = "0.1.0" + authors = [] + + [workspace] + members = ["ws-member"] + default-members = ["ws-member"] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "ws-member/Cargo.toml", + r#" + [package] + name = "ws-member" + version = "0.1.0" + authors = [] + "#, + ) + .file("ws-member/src/main.rs", "fn main() {}") + .build(); + + p.cargo("install --path") + .arg(p.root()) + .arg("ws-root") + .with_stderr_contains( + "[INSTALLED] package `ws-root v0.1.0 ([..])` (executable `ws-root[EXE]`)", + ) + // Particularly avoid "Installed package `ws-root v0.1.0 ([..]])` (executable `ws-member`)": + .with_stderr_does_not_contain("ws-member") + .run(); +} + #[cargo_test] fn dev_dependencies_no_check() { Package::new("foo", "1.0.0").publish();