mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-27 16:07:46 +00:00
Merge pull request #20920 from ShoyuVanilla/target-dirs
fix: Resolve `target-dir` more precisely
This commit is contained in:
commit
bacc5bbd30
@ -86,6 +86,7 @@ impl WorkspaceBuildScripts {
|
||||
config,
|
||||
&allowed_features,
|
||||
workspace.manifest_path(),
|
||||
workspace.target_directory().as_ref(),
|
||||
current_dir,
|
||||
sysroot,
|
||||
toolchain,
|
||||
@ -106,8 +107,9 @@ impl WorkspaceBuildScripts {
|
||||
let (_guard, cmd) = Self::build_command(
|
||||
config,
|
||||
&Default::default(),
|
||||
// This is not gonna be used anyways, so just construct a dummy here
|
||||
// These are not gonna be used anyways, so just construct a dummy here
|
||||
&ManifestPath::try_from(working_directory.clone()).unwrap(),
|
||||
working_directory.as_ref(),
|
||||
working_directory,
|
||||
&Sysroot::empty(),
|
||||
None,
|
||||
@ -430,6 +432,7 @@ impl WorkspaceBuildScripts {
|
||||
config: &CargoConfig,
|
||||
allowed_features: &FxHashSet<String>,
|
||||
manifest_path: &ManifestPath,
|
||||
target_dir: &Utf8Path,
|
||||
current_dir: &AbsPath,
|
||||
sysroot: &Sysroot,
|
||||
toolchain: Option<&semver::Version>,
|
||||
@ -450,8 +453,9 @@ impl WorkspaceBuildScripts {
|
||||
cmd.arg("--manifest-path");
|
||||
cmd.arg(manifest_path);
|
||||
|
||||
if let Some(target_dir) = &config.target_dir {
|
||||
cmd.arg("--target-dir").arg(target_dir);
|
||||
if let Some(target_dir) = config.target_dir_config.target_dir(Some(target_dir)) {
|
||||
cmd.arg("--target-dir");
|
||||
cmd.arg(target_dir.as_ref());
|
||||
}
|
||||
|
||||
if let Some(target) = &config.target {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
//! See [`CargoWorkspace`].
|
||||
|
||||
use std::ops;
|
||||
use std::str::from_utf8;
|
||||
use std::{borrow::Cow, ops, str::from_utf8};
|
||||
|
||||
use anyhow::Context;
|
||||
use base_db::Env;
|
||||
@ -95,6 +94,29 @@ impl Default for CargoFeatures {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum TargetDirectoryConfig {
|
||||
#[default]
|
||||
None,
|
||||
UseSubdirectory,
|
||||
Directory(Utf8PathBuf),
|
||||
}
|
||||
|
||||
impl TargetDirectoryConfig {
|
||||
pub fn target_dir<'a>(
|
||||
&'a self,
|
||||
ws_target_dir: Option<&'a Utf8Path>,
|
||||
) -> Option<Cow<'a, Utf8Path>> {
|
||||
match self {
|
||||
TargetDirectoryConfig::None => None,
|
||||
TargetDirectoryConfig::UseSubdirectory => {
|
||||
Some(Cow::Owned(ws_target_dir?.join("rust-analyzer")))
|
||||
}
|
||||
TargetDirectoryConfig::Directory(dir) => Some(Cow::Borrowed(dir)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CargoConfig {
|
||||
/// Whether to pass `--all-targets` to cargo invocations.
|
||||
@ -121,7 +143,7 @@ pub struct CargoConfig {
|
||||
pub extra_env: FxHashMap<String, Option<String>>,
|
||||
pub invocation_strategy: InvocationStrategy,
|
||||
/// Optional path to use instead of `target` when building
|
||||
pub target_dir: Option<Utf8PathBuf>,
|
||||
pub target_dir_config: TargetDirectoryConfig,
|
||||
/// Gate `#[test]` behind `#[cfg(test)]`
|
||||
pub set_test: bool,
|
||||
/// Load the project without any dependencies
|
||||
@ -715,21 +737,15 @@ impl FetchMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
|
||||
self.no_deps_result.as_ref().ok()
|
||||
}
|
||||
|
||||
/// Executes the metadata-fetching command.
|
||||
///
|
||||
/// A successful result may still contain a metadata error if the full fetch failed,
|
||||
/// but the fallback `--no-deps` pre-fetch succeeded during command construction.
|
||||
pub(crate) fn exec(
|
||||
self,
|
||||
target_dir: &Utf8Path,
|
||||
locked: bool,
|
||||
progress: &dyn Fn(String),
|
||||
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
|
||||
_ = target_dir;
|
||||
let Self {
|
||||
mut command,
|
||||
manifest_path: _,
|
||||
|
||||
@ -62,7 +62,7 @@ pub use crate::{
|
||||
build_dependencies::{ProcMacroDylibPath, WorkspaceBuildScripts},
|
||||
cargo_workspace::{
|
||||
CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
|
||||
PackageDependency, RustLibSource, Target, TargetData, TargetKind,
|
||||
PackageDependency, RustLibSource, Target, TargetData, TargetDirectoryConfig, TargetKind,
|
||||
},
|
||||
manifest_path::ManifestPath,
|
||||
project_json::{ProjectJson, ProjectJsonData},
|
||||
|
||||
@ -9,7 +9,7 @@ use std::{env, fs, ops::Not, path::Path, process::Command};
|
||||
|
||||
use anyhow::{Result, format_err};
|
||||
use itertools::Itertools;
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use stdx::format_to;
|
||||
use toolchain::{Tool, probe_for_binary};
|
||||
@ -219,7 +219,6 @@ impl Sysroot {
|
||||
&self,
|
||||
sysroot_source_config: &RustSourceWorkspaceConfig,
|
||||
no_deps: bool,
|
||||
target_dir: &Utf8Path,
|
||||
progress: &dyn Fn(String),
|
||||
) -> Option<RustLibSrcWorkspace> {
|
||||
assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
|
||||
@ -233,7 +232,6 @@ impl Sysroot {
|
||||
match self.load_library_via_cargo(
|
||||
&library_manifest,
|
||||
src_root,
|
||||
target_dir,
|
||||
cargo_config,
|
||||
no_deps,
|
||||
progress,
|
||||
@ -328,7 +326,6 @@ impl Sysroot {
|
||||
&self,
|
||||
library_manifest: &ManifestPath,
|
||||
current_dir: &AbsPath,
|
||||
target_dir: &Utf8Path,
|
||||
cargo_config: &CargoMetadataConfig,
|
||||
no_deps: bool,
|
||||
progress: &dyn Fn(String),
|
||||
@ -345,7 +342,7 @@ impl Sysroot {
|
||||
let locked = true;
|
||||
let (mut res, err) =
|
||||
FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
|
||||
.exec(target_dir, locked, progress)?;
|
||||
.exec(locked, progress)?;
|
||||
|
||||
// Patch out `rustc-std-workspace-*` crates to point to the real crates.
|
||||
// This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
|
||||
|
||||
@ -238,12 +238,8 @@ fn smoke_test_real_sysroot_cargo() {
|
||||
);
|
||||
let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
|
||||
std::fs::create_dir_all(&cwd).unwrap();
|
||||
let loaded_sysroot = sysroot.load_workspace(
|
||||
&RustSourceWorkspaceConfig::default_cargo(),
|
||||
false,
|
||||
&Utf8PathBuf::default(),
|
||||
&|_| (),
|
||||
);
|
||||
let loaded_sysroot =
|
||||
sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &|_| ());
|
||||
if let Some(loaded_sysroot) = loaded_sysroot {
|
||||
sysroot.set_workspace(loaded_sysroot);
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use semver::Version;
|
||||
use span::{Edition, FileId};
|
||||
use toolchain::{NO_RUSTUP_AUTO_INSTALL_ENV, Tool};
|
||||
use toolchain::Tool;
|
||||
use tracing::instrument;
|
||||
use tracing::{debug, error, info};
|
||||
use triomphe::Arc;
|
||||
@ -295,11 +295,6 @@ impl ProjectWorkspace {
|
||||
&sysroot,
|
||||
*no_deps,
|
||||
);
|
||||
let target_dir = config
|
||||
.target_dir
|
||||
.clone()
|
||||
.or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
|
||||
.unwrap_or_else(|| workspace_dir.join("target").into());
|
||||
|
||||
// We spawn a bunch of processes to query various information about the workspace's
|
||||
// toolchain and sysroot
|
||||
@ -345,7 +340,7 @@ impl ProjectWorkspace {
|
||||
},
|
||||
&sysroot,
|
||||
*no_deps,
|
||||
).exec(&target_dir, true, progress) {
|
||||
).exec(true, progress) {
|
||||
Ok((meta, _error)) => {
|
||||
let workspace = CargoWorkspace::new(
|
||||
meta,
|
||||
@ -374,7 +369,7 @@ impl ProjectWorkspace {
|
||||
})
|
||||
});
|
||||
|
||||
let cargo_metadata = s.spawn(|| fetch_metadata.exec(&target_dir, false, progress));
|
||||
let cargo_metadata = s.spawn(|| fetch_metadata.exec(false, progress));
|
||||
let loaded_sysroot = s.spawn(|| {
|
||||
sysroot.load_workspace(
|
||||
&RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
|
||||
@ -383,7 +378,6 @@ impl ProjectWorkspace {
|
||||
toolchain.clone(),
|
||||
)),
|
||||
config.no_deps,
|
||||
&target_dir,
|
||||
progress,
|
||||
)
|
||||
});
|
||||
@ -463,12 +457,6 @@ impl ProjectWorkspace {
|
||||
let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
|
||||
.unwrap_or_default();
|
||||
let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
|
||||
let project_root = project_json.project_root();
|
||||
let target_dir = config
|
||||
.target_dir
|
||||
.clone()
|
||||
.or_else(|| cargo_target_dir(project_json.manifest()?, &config.extra_env, &sysroot))
|
||||
.unwrap_or_else(|| project_root.join("target").into());
|
||||
|
||||
// We spawn a bunch of processes to query various information about the workspace's
|
||||
// toolchain and sysroot
|
||||
@ -486,7 +474,6 @@ impl ProjectWorkspace {
|
||||
sysroot.load_workspace(
|
||||
&RustSourceWorkspaceConfig::Json(*sysroot_project),
|
||||
config.no_deps,
|
||||
&target_dir,
|
||||
progress,
|
||||
)
|
||||
} else {
|
||||
@ -497,7 +484,6 @@ impl ProjectWorkspace {
|
||||
toolchain.clone(),
|
||||
)),
|
||||
config.no_deps,
|
||||
&target_dir,
|
||||
progress,
|
||||
)
|
||||
}
|
||||
@ -545,11 +531,6 @@ impl ProjectWorkspace {
|
||||
.unwrap_or_default();
|
||||
let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
|
||||
let target_data = target_data::get(query_config, None, &config.extra_env);
|
||||
let target_dir = config
|
||||
.target_dir
|
||||
.clone()
|
||||
.or_else(|| cargo_target_dir(detached_file, &config.extra_env, &sysroot))
|
||||
.unwrap_or_else(|| dir.join("target").into());
|
||||
|
||||
let loaded_sysroot = sysroot.load_workspace(
|
||||
&RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
|
||||
@ -558,7 +539,6 @@ impl ProjectWorkspace {
|
||||
toolchain.clone(),
|
||||
)),
|
||||
config.no_deps,
|
||||
&target_dir,
|
||||
&|_| (),
|
||||
);
|
||||
if let Some(loaded_sysroot) = loaded_sysroot {
|
||||
@ -579,21 +559,15 @@ impl ProjectWorkspace {
|
||||
&sysroot,
|
||||
config.no_deps,
|
||||
);
|
||||
let target_dir = config
|
||||
.target_dir
|
||||
.clone()
|
||||
.or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
|
||||
.unwrap_or_else(|| dir.join("target").into());
|
||||
let cargo_script =
|
||||
fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
|
||||
let cargo_config_extra_env =
|
||||
cargo_config_env(detached_file, &config_file, &config.extra_env);
|
||||
(
|
||||
CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
|
||||
WorkspaceBuildScripts::default(),
|
||||
error.map(Arc::new),
|
||||
)
|
||||
});
|
||||
let cargo_script = fetch_metadata.exec(false, &|_| ()).ok().map(|(ws, error)| {
|
||||
let cargo_config_extra_env =
|
||||
cargo_config_env(detached_file, &config_file, &config.extra_env);
|
||||
(
|
||||
CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
|
||||
WorkspaceBuildScripts::default(),
|
||||
error.map(Arc::new),
|
||||
)
|
||||
});
|
||||
|
||||
Ok(ProjectWorkspace {
|
||||
kind: ProjectWorkspaceKind::DetachedFile {
|
||||
@ -1902,25 +1876,3 @@ fn sysroot_metadata_config(
|
||||
kind: "sysroot",
|
||||
}
|
||||
}
|
||||
|
||||
fn cargo_target_dir(
|
||||
manifest: &ManifestPath,
|
||||
extra_env: &FxHashMap<String, Option<String>>,
|
||||
sysroot: &Sysroot,
|
||||
) -> Option<Utf8PathBuf> {
|
||||
let cargo = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
|
||||
let mut meta = cargo_metadata::MetadataCommand::new();
|
||||
meta.env(NO_RUSTUP_AUTO_INSTALL_ENV.0, NO_RUSTUP_AUTO_INSTALL_ENV.1);
|
||||
meta.cargo_path(cargo.get_program());
|
||||
meta.manifest_path(manifest);
|
||||
// `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
|
||||
// So we can use it to get `target_directory` before copying lockfiles
|
||||
meta.no_deps();
|
||||
let mut other_options = vec![];
|
||||
if manifest.is_rust_manifest() {
|
||||
meta.env("RUSTC_BOOTSTRAP", "1");
|
||||
other_options.push("-Zscript".to_owned());
|
||||
}
|
||||
meta.other_options(other_options);
|
||||
meta.exec().map(|m| m.target_directory).ok()
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ use hir::{ChangeWithProcMacros, Crate};
|
||||
use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
|
||||
use ide_db::base_db;
|
||||
use itertools::Either;
|
||||
use paths::Utf8PathBuf;
|
||||
use profile::StopWatch;
|
||||
use project_model::toolchain_info::{QueryConfig, target_data};
|
||||
use project_model::{
|
||||
@ -75,12 +74,8 @@ impl Tester {
|
||||
};
|
||||
|
||||
let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
|
||||
let loaded_sysroot = sysroot.load_workspace(
|
||||
&RustSourceWorkspaceConfig::default_cargo(),
|
||||
false,
|
||||
&Utf8PathBuf::default(),
|
||||
&|_| (),
|
||||
);
|
||||
let loaded_sysroot =
|
||||
sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &|_| ());
|
||||
if let Some(loaded_sysroot) = loaded_sysroot {
|
||||
sysroot.set_workspace(loaded_sysroot);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ use itertools::{Either, Itertools};
|
||||
use paths::{Utf8Path, Utf8PathBuf};
|
||||
use project_model::{
|
||||
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
|
||||
ProjectManifest, RustLibSource,
|
||||
ProjectManifest, RustLibSource, TargetDirectoryConfig,
|
||||
};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use semver::Version;
|
||||
@ -2301,7 +2301,7 @@ impl Config {
|
||||
run_build_script_command: self.cargo_buildScripts_overrideCommand(source_root).clone(),
|
||||
extra_args: self.cargo_extraArgs(source_root).clone(),
|
||||
extra_env: self.cargo_extraEnv(source_root).clone(),
|
||||
target_dir: self.target_dir_from_config(source_root),
|
||||
target_dir_config: self.target_dir_from_config(source_root),
|
||||
set_test: *self.cfg_setTest(source_root),
|
||||
no_deps: *self.cargo_noDeps(source_root),
|
||||
}
|
||||
@ -2389,7 +2389,7 @@ impl Config {
|
||||
extra_args: self.extra_args(source_root).clone(),
|
||||
extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
|
||||
extra_env: self.extra_env(source_root).clone(),
|
||||
target_dir: self.target_dir_from_config(source_root),
|
||||
target_dir_config: self.target_dir_from_config(source_root),
|
||||
set_test: true,
|
||||
}
|
||||
}
|
||||
@ -2447,7 +2447,7 @@ impl Config {
|
||||
extra_args: self.check_extra_args(source_root),
|
||||
extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
|
||||
extra_env: self.check_extra_env(source_root),
|
||||
target_dir: self.target_dir_from_config(source_root),
|
||||
target_dir_config: self.target_dir_from_config(source_root),
|
||||
set_test: *self.cfg_setTest(source_root),
|
||||
},
|
||||
ansi_color_output: self.color_diagnostic_output(),
|
||||
@ -2455,17 +2455,12 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
fn target_dir_from_config(&self, source_root: Option<SourceRootId>) -> Option<Utf8PathBuf> {
|
||||
self.cargo_targetDir(source_root).as_ref().and_then(|target_dir| match target_dir {
|
||||
TargetDirectory::UseSubdirectory(true) => {
|
||||
let env_var = env::var("CARGO_TARGET_DIR").ok();
|
||||
let mut path = Utf8PathBuf::from(env_var.as_deref().unwrap_or("target"));
|
||||
path.push("rust-analyzer");
|
||||
Some(path)
|
||||
}
|
||||
TargetDirectory::UseSubdirectory(false) => None,
|
||||
TargetDirectory::Directory(dir) => Some(dir.clone()),
|
||||
})
|
||||
fn target_dir_from_config(&self, source_root: Option<SourceRootId>) -> TargetDirectoryConfig {
|
||||
match &self.cargo_targetDir(source_root) {
|
||||
Some(TargetDirectory::UseSubdirectory(true)) => TargetDirectoryConfig::UseSubdirectory,
|
||||
Some(TargetDirectory::UseSubdirectory(false)) | None => TargetDirectoryConfig::None,
|
||||
Some(TargetDirectory::Directory(dir)) => TargetDirectoryConfig::Directory(dir.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_on_save(&self, source_root: Option<SourceRootId>) -> bool {
|
||||
@ -3991,7 +3986,7 @@ fn doc_comment_to_string(doc: &[&str]) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
use std::{borrow::Cow, fs};
|
||||
|
||||
use test_utils::{ensure_file_contents, project_root};
|
||||
|
||||
@ -4126,9 +4121,13 @@ mod tests {
|
||||
|
||||
(config, _, _) = config.apply_change(change);
|
||||
assert_eq!(config.cargo_targetDir(None), &None);
|
||||
assert!(
|
||||
matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
|
||||
);
|
||||
assert!(matches!(
|
||||
config.flycheck(None),
|
||||
FlycheckConfig::CargoCommand {
|
||||
options: CargoOptions { target_dir_config: TargetDirectoryConfig::None, .. },
|
||||
..
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -4144,11 +4143,16 @@ mod tests {
|
||||
(config, _, _) = config.apply_change(change);
|
||||
|
||||
assert_eq!(config.cargo_targetDir(None), &Some(TargetDirectory::UseSubdirectory(true)));
|
||||
let target =
|
||||
let ws_target_dir =
|
||||
Utf8PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned()));
|
||||
assert!(
|
||||
matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(target.join("rust-analyzer")))
|
||||
);
|
||||
assert!(matches!(
|
||||
config.flycheck(None),
|
||||
FlycheckConfig::CargoCommand {
|
||||
options: CargoOptions { target_dir_config, .. },
|
||||
..
|
||||
} if target_dir_config.target_dir(Some(&ws_target_dir)).map(Cow::into_owned)
|
||||
== Some(ws_target_dir.join("rust-analyzer"))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -4167,8 +4171,13 @@ mod tests {
|
||||
config.cargo_targetDir(None),
|
||||
&Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
|
||||
);
|
||||
assert!(
|
||||
matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
|
||||
);
|
||||
assert!(matches!(
|
||||
config.flycheck(None),
|
||||
FlycheckConfig::CargoCommand {
|
||||
options: CargoOptions { target_dir_config, .. },
|
||||
..
|
||||
} if target_dir_config.target_dir(None).map(Cow::into_owned)
|
||||
== Some(Utf8PathBuf::from("other_folder"))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ use crossbeam_channel::{Receiver, Sender, select_biased, unbounded};
|
||||
use ide_db::FxHashSet;
|
||||
use itertools::Itertools;
|
||||
use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
|
||||
use project_model::TargetDirectoryConfig;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize as _;
|
||||
use serde_derive::Deserialize;
|
||||
@ -46,7 +47,7 @@ pub(crate) struct CargoOptions {
|
||||
pub(crate) extra_args: Vec<String>,
|
||||
pub(crate) extra_test_bin_args: Vec<String>,
|
||||
pub(crate) extra_env: FxHashMap<String, Option<String>>,
|
||||
pub(crate) target_dir: Option<Utf8PathBuf>,
|
||||
pub(crate) target_dir_config: TargetDirectoryConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -58,7 +59,7 @@ pub(crate) enum Target {
|
||||
}
|
||||
|
||||
impl CargoOptions {
|
||||
pub(crate) fn apply_on_command(&self, cmd: &mut Command) {
|
||||
pub(crate) fn apply_on_command(&self, cmd: &mut Command, ws_target_dir: Option<&Utf8Path>) {
|
||||
for target in &self.target_tuples {
|
||||
cmd.args(["--target", target.as_str()]);
|
||||
}
|
||||
@ -82,8 +83,8 @@ impl CargoOptions {
|
||||
cmd.arg(self.features.join(" "));
|
||||
}
|
||||
}
|
||||
if let Some(target_dir) = &self.target_dir {
|
||||
cmd.arg("--target-dir").arg(target_dir);
|
||||
if let Some(target_dir) = self.target_dir_config.target_dir(ws_target_dir) {
|
||||
cmd.arg("--target-dir").arg(target_dir.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,6 +159,7 @@ impl FlycheckHandle {
|
||||
sysroot_root: Option<AbsPathBuf>,
|
||||
workspace_root: AbsPathBuf,
|
||||
manifest_path: Option<AbsPathBuf>,
|
||||
ws_target_dir: Option<Utf8PathBuf>,
|
||||
) -> FlycheckHandle {
|
||||
let actor = FlycheckActor::new(
|
||||
id,
|
||||
@ -167,6 +169,7 @@ impl FlycheckHandle {
|
||||
sysroot_root,
|
||||
workspace_root,
|
||||
manifest_path,
|
||||
ws_target_dir,
|
||||
);
|
||||
let (sender, receiver) = unbounded::<StateChange>();
|
||||
let thread =
|
||||
@ -314,6 +317,7 @@ struct FlycheckActor {
|
||||
sender: Sender<FlycheckMessage>,
|
||||
config: FlycheckConfig,
|
||||
manifest_path: Option<AbsPathBuf>,
|
||||
ws_target_dir: Option<Utf8PathBuf>,
|
||||
/// Either the workspace root of the workspace we are flychecking,
|
||||
/// or the project root of the project.
|
||||
root: Arc<AbsPathBuf>,
|
||||
@ -355,6 +359,7 @@ impl FlycheckActor {
|
||||
sysroot_root: Option<AbsPathBuf>,
|
||||
workspace_root: AbsPathBuf,
|
||||
manifest_path: Option<AbsPathBuf>,
|
||||
ws_target_dir: Option<Utf8PathBuf>,
|
||||
) -> FlycheckActor {
|
||||
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
|
||||
FlycheckActor {
|
||||
@ -366,6 +371,7 @@ impl FlycheckActor {
|
||||
root: Arc::new(workspace_root),
|
||||
scope: FlycheckScope::Workspace,
|
||||
manifest_path,
|
||||
ws_target_dir,
|
||||
command_handle: None,
|
||||
command_receiver: None,
|
||||
diagnostics_cleared_for: Default::default(),
|
||||
@ -428,15 +434,32 @@ impl FlycheckActor {
|
||||
CargoCheckParser,
|
||||
sender,
|
||||
match &self.config {
|
||||
FlycheckConfig::CargoCommand { options, .. } => Some(
|
||||
options
|
||||
.target_dir
|
||||
.as_deref()
|
||||
.unwrap_or(
|
||||
Utf8Path::new("target").join("rust-analyzer").as_path(),
|
||||
)
|
||||
.join(format!("flycheck{}", self.id)),
|
||||
),
|
||||
FlycheckConfig::CargoCommand { options, .. } => {
|
||||
let ws_target_dir =
|
||||
self.ws_target_dir.as_ref().map(Utf8PathBuf::as_path);
|
||||
let target_dir =
|
||||
options.target_dir_config.target_dir(ws_target_dir);
|
||||
|
||||
// If `"rust-analyzer.cargo.targetDir": null`, we should use
|
||||
// workspace's target dir instead of hard-coded fallback.
|
||||
let target_dir = target_dir.as_deref().or(ws_target_dir);
|
||||
|
||||
Some(
|
||||
// As `CommandHandle::spawn`'s working directory is
|
||||
// rust-analyzer's working directory, which might be different
|
||||
// from the flycheck's working directory, we should canonicalize
|
||||
// the output directory, otherwise we might write it into the
|
||||
// wrong target dir.
|
||||
// If `target_dir` is an absolute path, it will replace
|
||||
// `self.root` and that's an intended behavior.
|
||||
self.root
|
||||
.join(target_dir.unwrap_or(
|
||||
Utf8Path::new("target").join("rust-analyzer").as_path(),
|
||||
))
|
||||
.join(format!("flycheck{}", self.id))
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
) {
|
||||
@ -672,7 +695,10 @@ impl FlycheckActor {
|
||||
|
||||
cmd.arg("--keep-going");
|
||||
|
||||
options.apply_on_command(&mut cmd);
|
||||
options.apply_on_command(
|
||||
&mut cmd,
|
||||
self.ws_target_dir.as_ref().map(Utf8PathBuf::as_path),
|
||||
);
|
||||
cmd.args(&options.extra_args);
|
||||
Some(cmd)
|
||||
}
|
||||
|
||||
@ -284,6 +284,7 @@ pub(crate) fn handle_run_test(
|
||||
path,
|
||||
state.config.cargo_test_options(None),
|
||||
cargo.workspace_root(),
|
||||
Some(cargo.target_directory().as_ref()),
|
||||
target,
|
||||
state.test_run_sender.clone(),
|
||||
)?;
|
||||
|
||||
@ -23,6 +23,7 @@ use ide_db::{
|
||||
use itertools::Itertools;
|
||||
use load_cargo::{ProjectFolders, load_proc_macro};
|
||||
use lsp_types::FileSystemWatcher;
|
||||
use paths::Utf8Path;
|
||||
use proc_macro_api::ProcMacroClient;
|
||||
use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
|
||||
use stdx::{format_to, thread::ThreadIntent};
|
||||
@ -876,6 +877,7 @@ impl GlobalState {
|
||||
None,
|
||||
self.config.root_path().clone(),
|
||||
None,
|
||||
None,
|
||||
)]
|
||||
}
|
||||
crate::flycheck::InvocationStrategy::PerWorkspace => {
|
||||
@ -890,13 +892,17 @@ impl GlobalState {
|
||||
| ProjectWorkspaceKind::DetachedFile {
|
||||
cargo: Some((cargo, _, _)),
|
||||
..
|
||||
} => (cargo.workspace_root(), Some(cargo.manifest_path())),
|
||||
} => (
|
||||
cargo.workspace_root(),
|
||||
Some(cargo.manifest_path()),
|
||||
Some(cargo.target_directory()),
|
||||
),
|
||||
ProjectWorkspaceKind::Json(project) => {
|
||||
// Enable flychecks for json projects if a custom flycheck command was supplied
|
||||
// in the workspace configuration.
|
||||
match config {
|
||||
FlycheckConfig::CustomCommand { .. } => {
|
||||
(project.path(), None)
|
||||
(project.path(), None, None)
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
@ -906,7 +912,7 @@ impl GlobalState {
|
||||
ws.sysroot.root().map(ToOwned::to_owned),
|
||||
))
|
||||
})
|
||||
.map(|(id, (root, manifest_path), sysroot_root)| {
|
||||
.map(|(id, (root, manifest_path, target_dir), sysroot_root)| {
|
||||
FlycheckHandle::spawn(
|
||||
id,
|
||||
next_gen,
|
||||
@ -915,6 +921,7 @@ impl GlobalState {
|
||||
sysroot_root,
|
||||
root.to_path_buf(),
|
||||
manifest_path.map(|it| it.to_path_buf()),
|
||||
target_dir.map(|it| AsRef::<Utf8Path>::as_ref(it).to_path_buf()),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
//! thread and report the result of each test in a channel.
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use paths::AbsPath;
|
||||
use paths::{AbsPath, Utf8Path};
|
||||
use project_model::TargetKind;
|
||||
use serde::Deserialize as _;
|
||||
use serde_derive::Deserialize;
|
||||
@ -98,6 +98,7 @@ impl CargoTestHandle {
|
||||
path: Option<&str>,
|
||||
options: CargoOptions,
|
||||
root: &AbsPath,
|
||||
ws_target_dir: Option<&Utf8Path>,
|
||||
test_target: TestTarget,
|
||||
sender: Sender<CargoTestMessage>,
|
||||
) -> std::io::Result<Self> {
|
||||
@ -123,7 +124,7 @@ impl CargoTestHandle {
|
||||
cmd.arg("--no-fail-fast");
|
||||
cmd.arg("--manifest-path");
|
||||
cmd.arg(root.join("Cargo.toml"));
|
||||
options.apply_on_command(&mut cmd);
|
||||
options.apply_on_command(&mut cmd, ws_target_dir);
|
||||
cmd.arg("--");
|
||||
if let Some(path) = path {
|
||||
cmd.arg(path);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user