mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +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)]
|
||||
pub struct CargoConfig {
|
||||
/// Do not activate the `default` feature.
|
||||
|
@ -64,7 +73,7 @@ pub struct CargoConfig {
|
|||
pub no_sysroot: bool,
|
||||
|
||||
/// rustc private crate source
|
||||
pub rustc_source: Option<AbsPathBuf>,
|
||||
pub rustc_source: Option<RustcSource>,
|
||||
}
|
||||
|
||||
pub type Package = Idx<PackageData>;
|
||||
|
|
|
@ -21,8 +21,8 @@ use rustc_hash::FxHashSet;
|
|||
pub use crate::{
|
||||
build_data::{BuildDataCollector, BuildDataResult},
|
||||
cargo_workspace::{
|
||||
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData,
|
||||
TargetKind,
|
||||
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target,
|
||||
TargetData, TargetKind,
|
||||
},
|
||||
project_json::{ProjectJson, ProjectJsonData},
|
||||
sysroot::Sysroot,
|
||||
|
|
|
@ -51,11 +51,18 @@ impl Sysroot {
|
|||
pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
|
||||
log::debug!("Discovering sysroot for {}", cargo_toml.display());
|
||||
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)?;
|
||||
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> {
|
||||
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") {
|
||||
let path = AbsPathBuf::try_from(path.as_str())
|
||||
.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);
|
||||
}
|
||||
|
||||
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)
|
||||
.or_else(|| {
|
||||
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> {
|
||||
// Try the new path first since the old one still exists.
|
||||
let rust_src = sysroot_path.join("lib/rustlib/src/rust");
|
||||
|
|
|
@ -114,6 +114,7 @@ impl ProjectWorkspace {
|
|||
cargo_version
|
||||
)
|
||||
})?;
|
||||
|
||||
let sysroot = if config.no_sysroot {
|
||||
Sysroot::default()
|
||||
} 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(
|
||||
CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
|
||||
.with_context(|| {
|
||||
|
|
|
@ -18,7 +18,7 @@ use ide_db::helpers::{
|
|||
};
|
||||
use itertools::Itertools;
|
||||
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 serde::{de::DeserializeOwned, Deserialize};
|
||||
use vfs::AbsPathBuf;
|
||||
|
@ -177,8 +177,9 @@ config_data! {
|
|||
/// tests or binaries.\nFor example, it may be `--release`.
|
||||
runnables_cargoExtraArgs: Vec<String> = "[]",
|
||||
|
||||
/// Path to the rust compiler sources, for usage in rustc_private projects.
|
||||
rustcSource : Option<PathBuf> = "null",
|
||||
/// Path to the rust compiler sources, for usage in rustc_private projects, or "discover"
|
||||
/// to try to automatically find it.
|
||||
rustcSource : Option<String> = "null",
|
||||
|
||||
/// Additional arguments to `rustfmt`.
|
||||
rustfmt_extraArgs: Vec<String> = "[]",
|
||||
|
@ -473,7 +474,13 @@ impl Config {
|
|||
self.data.cargo_loadOutDirsFromCheck
|
||||
}
|
||||
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 {
|
||||
no_default_features: self.data.cargo_noDefaultFeatures,
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
[[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`.
|
||||
[[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: `[]`)::
|
||||
Additional arguments to `rustfmt`.
|
||||
[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
|
||||
|
|
|
@ -707,7 +707,7 @@
|
|||
}
|
||||
},
|
||||
"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,
|
||||
"type": [
|
||||
"null",
|
||||
|
|
|
@ -246,10 +246,10 @@ async function patchelf(dest: PathLike): Promise<void> {
|
|||
},
|
||||
async (progress, _) => {
|
||||
const expression = `
|
||||
{src, pkgs ? import <nixpkgs> {}}:
|
||||
{srcStr, pkgs ? import <nixpkgs> {}}:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "rust-analyzer";
|
||||
inherit src;
|
||||
src = /. + srcStr;
|
||||
phases = [ "installPhase" "fixupPhase" ];
|
||||
installPhase = "cp $src $out";
|
||||
fixupPhase = ''
|
||||
|
@ -262,7 +262,7 @@ async function patchelf(dest: PathLike): Promise<void> {
|
|||
await fs.rename(dest, origFile);
|
||||
progress.report({ message: "Patching executable", increment: 20 });
|
||||
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) => {
|
||||
if (err != null) {
|
||||
reject(Error(stderr));
|
||||
|
|
Loading…
Reference in a new issue