22//! Check the `rust-analyzer` user manual (<https://rust-analyzer.github.io/manual.html>),
33//! particularly the `rust-analyzer.workspace.discoverConfig` section, for more details.
44
5- use std:: convert:: TryFrom ;
6- use std:: env;
7- use std:: fs;
8- use std:: process:: Command ;
5+ use std:: { convert:: TryFrom , env, fs, io:: Write } ;
96
107use anyhow:: bail;
118use camino:: { Utf8Path , Utf8PathBuf } ;
129use clap:: Parser ;
13- use env_logger:: Target ;
14- use env_logger:: WriteStyle ;
15- use gen_rust_project_lib:: DiscoverProject ;
16- use gen_rust_project_lib:: NormalizedProjectString ;
17- use gen_rust_project_lib:: WORKSPACE_ROOT_FILE_NAMES ;
18- use gen_rust_project_lib:: { generate_crate_info, generate_rust_project, RustAnalyzerArg } ;
10+ use env_logger:: { Target , WriteStyle } ;
11+ use gen_rust_project_lib:: {
12+ generate_crate_info, generate_rust_project, get_bazel_info, DiscoverProject ,
13+ NormalizedProjectString , RustAnalyzerArg , WORKSPACE_ROOT_FILE_NAMES ,
14+ } ;
1915use log:: LevelFilter ;
20- use std:: io:: Write ;
2116
2217fn discover_rust_project (
2318 bazel : & Utf8Path ,
@@ -123,13 +118,7 @@ fn project_discovery() -> anyhow::Result<()> {
123118 log:: debug!( "got targets: {targets:?}" ) ;
124119
125120 // Generate the crate specs.
126- generate_crate_info (
127- & bazel,
128- & output_base,
129- & workspace,
130- rules_rust_name,
131- targets,
132- ) ?;
121+ generate_crate_info ( & bazel, & output_base, & workspace, rules_rust_name, targets) ?;
133122
134123 // Use the generated files to print the rust-project.json.
135124 discover_rust_project (
@@ -182,13 +171,16 @@ impl Config {
182171 // Parse the configuration flags and supplement with bazel info as needed.
183172 pub fn parse ( ) -> anyhow:: Result < Self > {
184173 let ConfigParser {
185- mut workspace,
186- mut execution_root,
187- mut output_base,
174+ workspace,
175+ execution_root,
176+ output_base,
188177 bazel,
189178 rust_analyzer_argument,
190179 } = ConfigParser :: parse ( ) ;
191180
181+ // Implemented this way instead of a classic `if let` to satisfy the
182+ // borrow checker.
183+ // See: <https://github.com/rust-lang/rust/issues/54663>
192184 if workspace. is_some ( ) && execution_root. is_some ( ) && output_base. is_some ( ) {
193185 return Ok ( Config {
194186 workspace : workspace. unwrap ( ) ,
@@ -200,48 +192,21 @@ impl Config {
200192 }
201193
202194 // We need some info from `bazel info`. Fetch it now.
203- let mut bazel_info_command = Command :: new ( & bazel) ;
204-
205- // Execute bazel info.
206- let output = bazel_info_command
207- // Switch to the workspace directory if one was provided.
208- . current_dir ( workspace. as_deref ( ) . unwrap_or ( Utf8Path :: new ( "." ) ) )
209- . env_remove ( "BAZELISK_SKIP_WRAPPER" )
210- . env_remove ( "BUILD_WORKING_DIRECTORY" )
211- . env_remove ( "BUILD_WORKSPACE_DIRECTORY" )
212- // Set the output_base if one was provided.
213- . args ( output_base. as_ref ( ) . map ( |s| format ! ( "--output_base={s}" ) ) )
214- . arg ( "info" )
215- . output ( ) ?;
216-
217- if !output. status . success ( ) {
218- let status = output. status ;
219- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
220- bail ! ( "Failed to run `bazel info` ({status:?}): {stderr}" ) ;
221- }
222-
223- // Extract the output.
224- let output = String :: from_utf8 ( output. stdout ) ?;
225-
226- let iter = output
227- . trim ( )
228- . split ( '\n' )
229- . filter_map ( |line| line. split_once ( ':' ) )
230- . map ( |( k, v) | ( k, v. trim ( ) ) ) ;
231-
232- for ( k, v) in iter {
233- match k {
234- "workspace" => workspace = Some ( v. into ( ) ) ,
235- "execution_root" => execution_root = Some ( v. into ( ) ) ,
236- "output_base" => output_base = Some ( v. into ( ) ) ,
237- _ => continue ,
238- }
239- }
195+ let mut info_map = get_bazel_info ( & bazel, workspace. as_deref ( ) , output_base. as_deref ( ) ) ?;
240196
241197 let config = Config {
242- workspace : workspace. expect ( "'workspace' must exist in bazel info" ) ,
243- execution_root : execution_root. expect ( "'execution_root' must exist in bazel info" ) ,
244- output_base : output_base. expect ( "'output_base' must exist in bazel info" ) ,
198+ workspace : info_map
199+ . remove ( "workspace" )
200+ . expect ( "'workspace' must exist in bazel info" )
201+ . into ( ) ,
202+ execution_root : info_map
203+ . remove ( "execution_root" )
204+ . expect ( "'execution_root' must exist in bazel info" )
205+ . into ( ) ,
206+ output_base : info_map
207+ . remove ( "output_base" )
208+ . expect ( "'output_base' must exist in bazel info" )
209+ . into ( ) ,
245210 bazel,
246211 rust_analyzer_argument,
247212 } ;
0 commit comments