Skip to content

Commit 7896110

Browse files
author
Bogdan Mircea
committed
add get_bazel_info function
1 parent 70d4489 commit 7896110

5 files changed

Lines changed: 96 additions & 125 deletions

File tree

tools/rust_analyzer/aquery.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use std::collections::{BTreeMap, BTreeSet};
2-
use std::fs::File;
3-
use std::process::Command;
1+
use std::{
2+
collections::{BTreeMap, BTreeSet},
3+
fs::File,
4+
process::Command,
5+
};
46

57
use anyhow::Context;
68
use camino::{Utf8Path, Utf8PathBuf};

tools/rust_analyzer/bin/discover_rust_project.rs

Lines changed: 26 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,17 @@
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

107
use anyhow::bail;
118
use camino::{Utf8Path, Utf8PathBuf};
129
use 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+
};
1915
use log::LevelFilter;
20-
use std::io::Write;
2116

2217
fn 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
};

tools/rust_analyzer/bin/gen_rust_project.rs

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use std::process::Command;
21
use std::{env, io::ErrorKind};
32

43
use anyhow::bail;
54
use camino::{Utf8Path, Utf8PathBuf};
65
use clap::Parser;
7-
use gen_rust_project_lib::{generate_crate_info, generate_rust_project, NormalizedProjectString};
6+
use gen_rust_project_lib::{
7+
generate_crate_info, generate_rust_project, get_bazel_info, NormalizedProjectString,
8+
};
89

910
fn write_rust_project(
1011
bazel: &Utf8Path,
@@ -59,13 +60,7 @@ fn main() -> anyhow::Result<()> {
5960
let rules_rust_name = env!("ASPECT_REPOSITORY");
6061

6162
// Generate the crate specs.
62-
generate_crate_info(
63-
&bazel,
64-
&output_base,
65-
&workspace,
66-
rules_rust_name,
67-
&targets,
68-
)?;
63+
generate_crate_info(&bazel, &output_base, &workspace, rules_rust_name, &targets)?;
6964

7065
// Use the generated files to write rust-project.json.
7166
write_rust_project(
@@ -103,13 +98,16 @@ impl Config {
10398
// Parse the configuration flags and supplement with bazel info as needed.
10499
pub fn parse() -> anyhow::Result<Self> {
105100
let ConfigParser {
106-
mut workspace,
107-
mut execution_root,
108-
mut output_base,
101+
workspace,
102+
execution_root,
103+
output_base,
109104
bazel,
110105
targets,
111106
} = ConfigParser::parse();
112107

108+
// Implemented this way instead of a classic `if let` to satisfy the
109+
// borrow checker.
110+
// See: <https://github.com/rust-lang/rust/issues/54663>
113111
if workspace.is_some() && execution_root.is_some() && output_base.is_some() {
114112
return Ok(Config {
115113
workspace: workspace.unwrap(),
@@ -121,48 +119,21 @@ impl Config {
121119
}
122120

123121
// We need some info from `bazel info`. Fetch it now.
124-
let mut bazel_info_command = Command::new(&bazel);
125-
126-
// Execute bazel info.
127-
let output = bazel_info_command
128-
// Switch to the workspace directory if one was provided.
129-
.current_dir(workspace.as_deref().unwrap_or(Utf8Path::new(".")))
130-
.env_remove("BAZELISK_SKIP_WRAPPER")
131-
.env_remove("BUILD_WORKING_DIRECTORY")
132-
.env_remove("BUILD_WORKSPACE_DIRECTORY")
133-
// Set the output_base if one was provided.
134-
.args(output_base.as_ref().map(|s| format!("--output_base={s}")))
135-
.arg("info")
136-
.output()?;
137-
138-
if !output.status.success() {
139-
let status = output.status;
140-
let stderr = String::from_utf8_lossy(&output.stderr);
141-
bail!("Failed to run `bazel info` ({status:?}): {stderr}");
142-
}
143-
144-
// Extract the output.
145-
let output = String::from_utf8(output.stdout)?;
146-
147-
let iter = output
148-
.trim()
149-
.split('\n')
150-
.filter_map(|line| line.split_once(':'))
151-
.map(|(k, v)| (k, v.trim()));
152-
153-
for (k, v) in iter {
154-
match k {
155-
"workspace" => workspace = Some(v.into()),
156-
"execution_root" => execution_root = Some(v.into()),
157-
"output_base" => output_base = Some(v.into()),
158-
_ => continue,
159-
}
160-
}
122+
let mut info_map = get_bazel_info(&bazel, workspace.as_deref(), output_base.as_deref())?;
161123

162124
let config = Config {
163-
workspace: workspace.expect("'workspace' must exist in bazel info"),
164-
execution_root: execution_root.expect("'execution_root' must exist in bazel info"),
165-
output_base: output_base.expect("'output_base' must exist in bazel info"),
125+
workspace: info_map
126+
.remove("workspace")
127+
.expect("'workspace' must exist in bazel info")
128+
.into(),
129+
execution_root: info_map
130+
.remove("execution_root")
131+
.expect("'execution_root' must exist in bazel info")
132+
.into(),
133+
output_base: info_map
134+
.remove("output_base")
135+
.expect("'output_base' must exist in bazel info")
136+
.into(),
166137
bazel,
167138
targets,
168139
};

tools/rust_analyzer/lib.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
mod aquery;
22
mod rust_project;
33

4-
use std::collections::HashMap;
5-
use std::process::Command;
4+
use std::{collections::HashMap, process::Command};
65

76
use anyhow::bail;
87
use camino::Utf8Path;
@@ -83,3 +82,37 @@ pub fn generate_rust_project(
8382

8483
rust_project::assemble_rust_project(bazel, workspace, sysroot, sysroot_src, &crate_specs)
8584
}
85+
86+
/// Executes `bazel info` to get context information.
87+
pub fn get_bazel_info(
88+
bazel: &Utf8Path,
89+
workspace: Option<&Utf8Path>,
90+
output_base: Option<&Utf8Path>,
91+
) -> anyhow::Result<HashMap<String, String>> {
92+
let output = Command::new(&bazel)
93+
// Switch to the workspace directory if one was provided.
94+
.current_dir(workspace.unwrap_or(Utf8Path::new(".")))
95+
.env_remove("BAZELISK_SKIP_WRAPPER")
96+
.env_remove("BUILD_WORKING_DIRECTORY")
97+
.env_remove("BUILD_WORKSPACE_DIRECTORY")
98+
// Set the output_base if one was provided.
99+
.args(output_base.map(|s| format!("--output_base={s}")))
100+
.arg("info")
101+
.output()?;
102+
103+
if !output.status.success() {
104+
let status = output.status;
105+
let stderr = String::from_utf8_lossy(&output.stderr);
106+
bail!("Failed to run `bazel info` ({status:?}): {stderr}");
107+
}
108+
109+
// Extract and parse the output.
110+
let info_map = String::from_utf8(output.stdout)?
111+
.trim()
112+
.split('\n')
113+
.filter_map(|line| line.split_once(':'))
114+
.map(|(k, v)| (k.to_owned(), v.trim().to_owned()))
115+
.collect();
116+
117+
Ok(info_map)
118+
}

tools/rust_analyzer/rust_project.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
//! Library for generating rust_project.json files from a `Vec<CrateSpec>`
22
//! See official documentation of file format at https://rust-analyzer.github.io/manual.html
33
4-
use std::collections::{BTreeMap, BTreeSet, HashMap};
5-
use std::convert::TryFrom;
6-
use std::fmt::Display;
7-
use std::fs;
8-
use std::str::FromStr;
4+
use std::collections::{
5+
convert::TryFrom, fmt::Display, fs, str::FromStr, BTreeMap, BTreeSet, HashMap,
6+
};
97

108
use anyhow::{anyhow, bail, Context};
119
use camino::{Utf8Path, Utf8PathBuf};
1210
use serde::{Deserialize, Serialize};
1311

14-
use crate::aquery::{CrateSpec, CrateType};
15-
use crate::BUILD_FILE_NAMES;
12+
use crate::{
13+
aquery::{CrateSpec, CrateType},
14+
BUILD_FILE_NAMES,
15+
};
1616

1717
/// The argument that `rust-analyzer` can pass to the workspace discovery command.
1818
#[derive(Clone, Debug, Deserialize, Serialize)]

0 commit comments

Comments
 (0)