mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
7643: Automatically detect the rustc-src directory (fixes #3517) r=matklad a=bnjbvr If the configured rustcSource was not set, then try to automatically detect a source for the sysroot rustc directory. I wasn't sure how to do it in the case of the project.json file, though. 7663: Tolerate spaces in nix binary patching r=matklad a=CertainLach If path to original file contains space (I.e on code insiders, where default data directory is ~/Code - Insiders/), then there is syntax error evaluating src arg. Instead pass path as str, and coerce to path back in nix expression Co-authored-by: Benjamin Bouvier <public@benj.me> Co-authored-by: Yaroslav Bolyukin <iam@lach.pw>
This commit is contained in:
commit
d50a37d3aa
8 changed files with 70 additions and 23 deletions
|
@ -44,6 +44,15 @@ impl ops::Index<Target> for CargoWorkspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes how to set the rustc source directory.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum RustcSource {
|
||||||
|
/// Explicit path for the rustc source directory.
|
||||||
|
Path(AbsPathBuf),
|
||||||
|
/// Try to automatically detect where the rustc source directory is.
|
||||||
|
Discover,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CargoConfig {
|
pub struct CargoConfig {
|
||||||
/// Do not activate the `default` feature.
|
/// Do not activate the `default` feature.
|
||||||
|
@ -64,7 +73,7 @@ pub struct CargoConfig {
|
||||||
pub no_sysroot: bool,
|
pub no_sysroot: bool,
|
||||||
|
|
||||||
/// rustc private crate source
|
/// rustc private crate source
|
||||||
pub rustc_source: Option<AbsPathBuf>,
|
pub rustc_source: Option<RustcSource>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Package = Idx<PackageData>;
|
pub type Package = Idx<PackageData>;
|
||||||
|
|
|
@ -21,8 +21,8 @@ use rustc_hash::FxHashSet;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
build_data::{BuildDataCollector, BuildDataResult},
|
build_data::{BuildDataCollector, BuildDataResult},
|
||||||
cargo_workspace::{
|
cargo_workspace::{
|
||||||
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData,
|
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target,
|
||||||
TargetKind,
|
TargetData, TargetKind,
|
||||||
},
|
},
|
||||||
project_json::{ProjectJson, ProjectJsonData},
|
project_json::{ProjectJson, ProjectJsonData},
|
||||||
sysroot::Sysroot,
|
sysroot::Sysroot,
|
||||||
|
|
|
@ -51,11 +51,18 @@ impl Sysroot {
|
||||||
pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
|
pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
|
||||||
log::debug!("Discovering sysroot for {}", cargo_toml.display());
|
log::debug!("Discovering sysroot for {}", cargo_toml.display());
|
||||||
let current_dir = cargo_toml.parent().unwrap();
|
let current_dir = cargo_toml.parent().unwrap();
|
||||||
let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
|
let sysroot_dir = discover_sysroot_dir(current_dir)?;
|
||||||
|
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, current_dir)?;
|
||||||
let res = Sysroot::load(&sysroot_src_dir)?;
|
let res = Sysroot::load(&sysroot_src_dir)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn discover_rustc(cargo_toml: &AbsPath) -> Option<AbsPathBuf> {
|
||||||
|
log::debug!("Discovering rustc source for {}", cargo_toml.display());
|
||||||
|
let current_dir = cargo_toml.parent().unwrap();
|
||||||
|
discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
|
pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
|
||||||
let mut sysroot = Sysroot { crates: Arena::default() };
|
let mut sysroot = Sysroot { crates: Arena::default() };
|
||||||
|
|
||||||
|
@ -110,7 +117,18 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
|
fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
|
||||||
|
let mut rustc = Command::new(toolchain::rustc());
|
||||||
|
rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
|
||||||
|
log::debug!("Discovering sysroot by {:?}", rustc);
|
||||||
|
let stdout = utf8_stdout(rustc)?;
|
||||||
|
Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discover_sysroot_src_dir(
|
||||||
|
sysroot_path: &AbsPathBuf,
|
||||||
|
current_dir: &AbsPath,
|
||||||
|
) -> Result<AbsPathBuf> {
|
||||||
if let Ok(path) = env::var("RUST_SRC_PATH") {
|
if let Ok(path) = env::var("RUST_SRC_PATH") {
|
||||||
let path = AbsPathBuf::try_from(path.as_str())
|
let path = AbsPathBuf::try_from(path.as_str())
|
||||||
.map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
|
.map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
|
||||||
|
@ -122,14 +140,6 @@ fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
|
||||||
log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
|
log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysroot_path = {
|
|
||||||
let mut rustc = Command::new(toolchain::rustc());
|
|
||||||
rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
|
|
||||||
log::debug!("Discovering sysroot by {:?}", rustc);
|
|
||||||
let stdout = utf8_stdout(rustc)?;
|
|
||||||
AbsPathBuf::assert(PathBuf::from(stdout))
|
|
||||||
};
|
|
||||||
|
|
||||||
get_rust_src(&sysroot_path)
|
get_rust_src(&sysroot_path)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let mut rustup = Command::new(toolchain::rustup());
|
let mut rustup = Command::new(toolchain::rustup());
|
||||||
|
@ -149,6 +159,16 @@ try installing the Rust source the same way you installed rustc",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_rustc_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
|
||||||
|
let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
|
||||||
|
log::debug!("Checking for rustc source code: {}", rustc_src.display());
|
||||||
|
if rustc_src.exists() {
|
||||||
|
Some(rustc_src)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
|
fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
|
||||||
// Try the new path first since the old one still exists.
|
// Try the new path first since the old one still exists.
|
||||||
let rust_src = sysroot_path.join("lib/rustlib/src/rust");
|
let rust_src = sysroot_path.join("lib/rustlib/src/rust");
|
||||||
|
|
|
@ -114,6 +114,7 @@ impl ProjectWorkspace {
|
||||||
cargo_version
|
cargo_version
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let sysroot = if config.no_sysroot {
|
let sysroot = if config.no_sysroot {
|
||||||
Sysroot::default()
|
Sysroot::default()
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,7 +126,17 @@ impl ProjectWorkspace {
|
||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
let rustc = if let Some(rustc_dir) = &config.rustc_source {
|
let rustc_dir = if let Some(rustc_source) = &config.rustc_source {
|
||||||
|
use cargo_workspace::RustcSource;
|
||||||
|
match rustc_source {
|
||||||
|
RustcSource::Path(path) => Some(path.clone()),
|
||||||
|
RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let rustc = if let Some(rustc_dir) = rustc_dir {
|
||||||
Some(
|
Some(
|
||||||
CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
|
CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use ide_db::helpers::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lsp_types::{ClientCapabilities, MarkupKind};
|
use lsp_types::{ClientCapabilities, MarkupKind};
|
||||||
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
|
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::{de::DeserializeOwned, Deserialize};
|
||||||
use vfs::AbsPathBuf;
|
use vfs::AbsPathBuf;
|
||||||
|
@ -177,8 +177,9 @@ config_data! {
|
||||||
/// tests or binaries.\nFor example, it may be `--release`.
|
/// tests or binaries.\nFor example, it may be `--release`.
|
||||||
runnables_cargoExtraArgs: Vec<String> = "[]",
|
runnables_cargoExtraArgs: Vec<String> = "[]",
|
||||||
|
|
||||||
/// Path to the rust compiler sources, for usage in rustc_private projects.
|
/// Path to the rust compiler sources, for usage in rustc_private projects, or "discover"
|
||||||
rustcSource : Option<PathBuf> = "null",
|
/// to try to automatically find it.
|
||||||
|
rustcSource : Option<String> = "null",
|
||||||
|
|
||||||
/// Additional arguments to `rustfmt`.
|
/// Additional arguments to `rustfmt`.
|
||||||
rustfmt_extraArgs: Vec<String> = "[]",
|
rustfmt_extraArgs: Vec<String> = "[]",
|
||||||
|
@ -473,7 +474,13 @@ impl Config {
|
||||||
self.data.cargo_loadOutDirsFromCheck
|
self.data.cargo_loadOutDirsFromCheck
|
||||||
}
|
}
|
||||||
pub fn cargo(&self) -> CargoConfig {
|
pub fn cargo(&self) -> CargoConfig {
|
||||||
let rustc_source = self.data.rustcSource.as_ref().map(|it| self.root_path.join(&it));
|
let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| {
|
||||||
|
if rustc_src == "discover" {
|
||||||
|
RustcSource::Discover
|
||||||
|
} else {
|
||||||
|
RustcSource::Path(self.root_path.join(rustc_src))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
CargoConfig {
|
CargoConfig {
|
||||||
no_default_features: self.data.cargo_noDefaultFeatures,
|
no_default_features: self.data.cargo_noDefaultFeatures,
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
[[rust-analyzer.runnables.cargoExtraArgs]]rust-analyzer.runnables.cargoExtraArgs (default: `[]`)::
|
[[rust-analyzer.runnables.cargoExtraArgs]]rust-analyzer.runnables.cargoExtraArgs (default: `[]`)::
|
||||||
Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`.
|
Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`.
|
||||||
[[rust-analyzer.rustcSource]]rust-analyzer.rustcSource (default: `null`)::
|
[[rust-analyzer.rustcSource]]rust-analyzer.rustcSource (default: `null`)::
|
||||||
Path to the rust compiler sources, for usage in rustc_private projects.
|
Path to the rust compiler sources, for usage in rustc_private projects, or "discover" to try to automatically find it.
|
||||||
[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
|
[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
|
||||||
Additional arguments to `rustfmt`.
|
Additional arguments to `rustfmt`.
|
||||||
[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
|
[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
|
||||||
|
|
|
@ -707,7 +707,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-analyzer.rustcSource": {
|
"rust-analyzer.rustcSource": {
|
||||||
"markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects.",
|
"markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects, or \"discover\" to try to automatically find it.",
|
||||||
"default": null,
|
"default": null,
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|
|
@ -246,10 +246,10 @@ async function patchelf(dest: PathLike): Promise<void> {
|
||||||
},
|
},
|
||||||
async (progress, _) => {
|
async (progress, _) => {
|
||||||
const expression = `
|
const expression = `
|
||||||
{src, pkgs ? import <nixpkgs> {}}:
|
{srcStr, pkgs ? import <nixpkgs> {}}:
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "rust-analyzer";
|
name = "rust-analyzer";
|
||||||
inherit src;
|
src = /. + srcStr;
|
||||||
phases = [ "installPhase" "fixupPhase" ];
|
phases = [ "installPhase" "fixupPhase" ];
|
||||||
installPhase = "cp $src $out";
|
installPhase = "cp $src $out";
|
||||||
fixupPhase = ''
|
fixupPhase = ''
|
||||||
|
@ -262,7 +262,7 @@ async function patchelf(dest: PathLike): Promise<void> {
|
||||||
await fs.rename(dest, origFile);
|
await fs.rename(dest, origFile);
|
||||||
progress.report({ message: "Patching executable", increment: 20 });
|
progress.report({ message: "Patching executable", increment: 20 });
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`,
|
const handle = exec(`nix-build -E - --argstr srcStr '${origFile}' -o '${dest}'`,
|
||||||
(err, stdout, stderr) => {
|
(err, stdout, stderr) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
reject(Error(stderr));
|
reject(Error(stderr));
|
||||||
|
|
Loading…
Reference in a new issue