1 use std::collections::HashMap;
2 use std::path::Path;
3 use std::process::Command;
4
5 use anyhow::anyhow;
6 use runfiles::Runfiles;
7
8 mod aquery;
9 mod rust_project;
10
11 const SYSROOT_SRC_FILE_RUNFILES_PREFIX: &str = "rules_rust";
12
generate_crate_info( bazel: impl AsRef<Path>, workspace: impl AsRef<Path>, rules_rust: impl AsRef<str>, targets: &[String], ) -> anyhow::Result<()>13 pub fn generate_crate_info(
14 bazel: impl AsRef<Path>,
15 workspace: impl AsRef<Path>,
16 rules_rust: impl AsRef<str>,
17 targets: &[String],
18 ) -> anyhow::Result<()> {
19 log::debug!("Building rust_analyzer_crate_spec files for {:?}", targets);
20
21 let output = Command::new(bazel.as_ref())
22 .current_dir(workspace.as_ref())
23 .env_remove("BAZELISK_SKIP_WRAPPER")
24 .env_remove("BUILD_WORKING_DIRECTORY")
25 .env_remove("BUILD_WORKSPACE_DIRECTORY")
26 .arg("build")
27 .arg("--norun_validations")
28 .arg(format!(
29 "--aspects={}//rust:defs.bzl%rust_analyzer_aspect",
30 rules_rust.as_ref()
31 ))
32 .arg("--output_groups=rust_analyzer_crate_spec")
33 .args(targets)
34 .output()?;
35
36 if !output.status.success() {
37 return Err(anyhow!(
38 "bazel build failed:({})\n{}",
39 output.status,
40 String::from_utf8_lossy(&output.stderr)
41 ));
42 }
43
44 Ok(())
45 }
46
write_rust_project( bazel: impl AsRef<Path>, workspace: impl AsRef<Path>, rules_rust_name: &impl AsRef<str>, targets: &[String], execution_root: impl AsRef<Path>, output_base: impl AsRef<Path>, rust_project_path: impl AsRef<Path>, ) -> anyhow::Result<()>47 pub fn write_rust_project(
48 bazel: impl AsRef<Path>,
49 workspace: impl AsRef<Path>,
50 rules_rust_name: &impl AsRef<str>,
51 targets: &[String],
52 execution_root: impl AsRef<Path>,
53 output_base: impl AsRef<Path>,
54 rust_project_path: impl AsRef<Path>,
55 ) -> anyhow::Result<()> {
56 let crate_specs = aquery::get_crate_specs(
57 bazel.as_ref(),
58 workspace.as_ref(),
59 execution_root.as_ref(),
60 targets,
61 rules_rust_name.as_ref(),
62 )?;
63
64 let workspace_name = match rules_rust_name.as_ref().trim_start_matches('@') {
65 "" => SYSROOT_SRC_FILE_RUNFILES_PREFIX,
66 s => s,
67 };
68 let toolchain_info_path = format!(
69 "{workspace_name}/rust/private/rust_analyzer_detect_sysroot.rust_analyzer_toolchain.json"
70 );
71 let r = Runfiles::create()?;
72 let path = r.rlocation(toolchain_info_path);
73 let toolchain_info: HashMap<String, String> =
74 serde_json::from_str(&std::fs::read_to_string(path)?)?;
75
76 let sysroot_src = &toolchain_info["sysroot_src"];
77 let sysroot = &toolchain_info["sysroot"];
78
79 let rust_project = rust_project::generate_rust_project(sysroot, sysroot_src, &crate_specs)?;
80
81 rust_project::write_rust_project(
82 rust_project_path.as_ref(),
83 execution_root.as_ref(),
84 output_base.as_ref(),
85 &rust_project,
86 )?;
87
88 Ok(())
89 }
90