diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 9c897ae1bb784..1f56329cbcd07 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -2,6 +2,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; use crate::utils::helpers::hex_encode; +use crate::utils::ra_project::RustAnalyzerProject; use crate::Config; use sha2::Digest; use std::env::consts::EXE_SUFFIX; @@ -624,3 +625,54 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result { } Ok(should_create) } + +/// Sets up `rust-project.json` +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct RustProjectJson; + +impl Step for RustProjectJson { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("rust-project") + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "rust-project" { + run.builder.ensure(RustProjectJson); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + + while !t!(create_ra_project_json_maybe(&config)) {} + } +} + +fn create_ra_project_json_maybe(config: &Config) -> io::Result { + println!("\nx.py can automatically generate `rust-project.json` file for rust-analyzer"); + + let should_create = match prompt_user("Would you like to create rust-project.json?: [y/N]")? { + Some(PromptResult::Yes) => true, + _ => { + println!("Ok, skipping rust-project.json!"); + return Ok(true); + } + }; + + if should_create { + let ra_project = RustAnalyzerProject::collect_ra_project_data(&config); + ra_project.generate_file(&config.src.join("rust-project.json"))?; + println!("Created `rust-project.json`"); + } + + Ok(should_create) +} diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 4e20babc55a68..6451c1dc3076b 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -880,7 +880,13 @@ impl<'a> Builder<'a> { run::GenerateWindowsSys, run::GenerateCompletions, ), - Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), + Kind::Setup => describe!( + setup::Profile, + setup::Hook, + setup::Link, + setup::Vscode, + setup::RustProjectJson + ), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), // special-cased in Build::build() Kind::Format | Kind::Suggest => vec![], diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 66372eeb3f652..ce3f1a8fde6cf 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -5,7 +5,7 @@ use serde_derive::Deserialize; use crate::utils::cache::INTERNER; use crate::utils::helpers::output; -use crate::{t, Build, Crate}; +use crate::{t, Build, Config, Crate}; /// For more information, see the output of /// @@ -45,7 +45,7 @@ pub(crate) struct Target { /// Collects and stores package metadata of each workspace members into `build`, /// by executing `cargo metadata` commands. pub fn build(build: &mut Build) { - for package in workspace_members(build) { + for package in workspace_members(&build.config) { if package.source.is_none() { let name = INTERNER.intern_string(package.name); let mut path = PathBuf::from(package.manifest_path); @@ -74,9 +74,9 @@ pub fn build(build: &mut Build) { /// /// Note that `src/tools/cargo` is no longer a workspace member but we still /// treat it as one here, by invoking an additional `cargo metadata` command. -pub(crate) fn workspace_members(build: &Build) -> impl Iterator { +pub(crate) fn workspace_members(config: &Config) -> impl Iterator { let collect_metadata = |manifest_path| { - let mut cargo = Command::new(&build.initial_cargo); + let mut cargo = Command::new(&config.initial_cargo); cargo // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -86,7 +86,7 @@ pub(crate) fn workspace_members(build: &Build) -> impl Iterator .arg("1") .arg("--no-deps") .arg("--manifest-path") - .arg(build.src.join(manifest_path)); + .arg(config.src.join(manifest_path)); let metadata_output = output(&mut cargo); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages @@ -105,9 +105,9 @@ pub(crate) fn workspace_members(build: &Build) -> impl Iterator } /// Invokes `cargo metadata` to get package metadata of whole workspace including the dependencies. -pub(crate) fn project_metadata(build: &Build) -> impl Iterator { +pub(crate) fn project_metadata(config: &Config) -> impl Iterator { let collect_metadata = |manifest_path| { - let mut cargo = Command::new(&build.initial_cargo); + let mut cargo = Command::new(&config.initial_cargo); cargo // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -116,7 +116,7 @@ pub(crate) fn project_metadata(build: &Build) -> impl Iterator { .arg("--format-version") .arg("1") .arg("--manifest-path") - .arg(build.src.join(manifest_path)); + .arg(config.src.join(manifest_path)); let metadata_output = output(&mut cargo); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages diff --git a/src/bootstrap/src/utils/ra_project.rs b/src/bootstrap/src/utils/ra_project.rs index 74b57f6f67df4..7afd2bace4be6 100644 --- a/src/bootstrap/src/utils/ra_project.rs +++ b/src/bootstrap/src/utils/ra_project.rs @@ -15,11 +15,11 @@ use std::io; use std::path::Path; use crate::core::metadata::{project_metadata, workspace_members, Dependency}; -use crate::Build; +use crate::Config; #[derive(Debug, Deserialize, Serialize)] /// FIXME(before-merge): doc-comment -struct RustAnalyzerProject { +pub(crate) struct RustAnalyzerProject { crates: Vec, sysroot: String, sysroot_src: String, @@ -33,6 +33,7 @@ struct Crate { edition: String, env: BTreeMap, is_proc_macro: bool, + #[serde(skip_serializing_if = "Option::is_none")] proc_macro_dylib_path: Option, is_workspace_member: bool, root_module: String, @@ -47,15 +48,15 @@ struct Dep { impl RustAnalyzerProject { #[allow(dead_code)] // FIXME(before-merge): remove this - pub(crate) fn collect_ra_project_data(build: &mut Build) -> Self { + pub(crate) fn collect_ra_project_data(config: &Config) -> Self { let mut ra_project = RustAnalyzerProject { crates: vec![], - sysroot: format!("{}", build.out.join("host").join("stage0").display()), - sysroot_src: format!("{}", build.src.join("library").display()), + sysroot: format!("{}", config.out.join("host").join("stage0").display()), + sysroot_src: format!("{}", config.src.join("library").display()), }; - let packages: Vec<_> = project_metadata(build).collect(); - let workspace_members: Vec<_> = workspace_members(build).collect(); + let packages: Vec<_> = project_metadata(config).collect(); + let workspace_members: Vec<_> = workspace_members(config).collect(); for package in &packages { let is_not_indirect_dependency = packages @@ -94,7 +95,7 @@ impl RustAnalyzerProject { if target .src_path - .starts_with(&build.src.join("library").to_string_lossy().to_string()) + .starts_with(&config.src.join("library").to_string_lossy().to_string()) { krate.cfg.push("bootstrap".into()); }