Skip to content

Commit 84302bd

Browse files
bors[bot]matklad
andauthored
Merge #9638
9638: internal: replace some unwraps with types r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 1dc3376 + 52a70c3 commit 84302bd

File tree

7 files changed

+125
-94
lines changed

7 files changed

+125
-94
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! See [`CargoWorkspace`].
22
3+
use std::convert::TryInto;
34
use std::iter;
45
use std::path::PathBuf;
5-
use std::{convert::TryInto, ops, process::Command};
6+
use std::{ops, process::Command};
67

78
use anyhow::{Context, Result};
89
use base_db::Edition;
@@ -13,8 +14,8 @@ use rustc_hash::FxHashMap;
1314
use serde::Deserialize;
1415
use serde_json::from_value;
1516

16-
use crate::utf8_stdout;
1717
use crate::CfgOverrides;
18+
use crate::{utf8_stdout, ManifestPath};
1819

1920
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
2021
/// workspace. It pretty closely mirrors `cargo metadata` output.
@@ -108,7 +109,7 @@ pub struct PackageData {
108109
/// Name as given in the `Cargo.toml`
109110
pub name: String,
110111
/// Path containing the `Cargo.toml`
111-
pub manifest: AbsPathBuf,
112+
pub manifest: ManifestPath,
112113
/// Targets provided by the crate (lib, bin, example, test, ...)
113114
pub targets: Vec<Target>,
114115
/// Is this package a member of the current workspace
@@ -215,12 +216,6 @@ impl TargetKind {
215216
}
216217
}
217218

218-
impl PackageData {
219-
pub fn root(&self) -> &AbsPath {
220-
self.manifest.parent().unwrap()
221-
}
222-
}
223-
224219
#[derive(Deserialize, Default)]
225220
// Deserialise helper for the cargo metadata
226221
struct PackageMetadata {
@@ -230,10 +225,16 @@ struct PackageMetadata {
230225

231226
impl CargoWorkspace {
232227
pub fn fetch_metadata(
233-
cargo_toml: &AbsPath,
228+
cargo_toml: &ManifestPath,
234229
config: &CargoConfig,
235230
progress: &dyn Fn(String),
236231
) -> Result<cargo_metadata::Metadata> {
232+
let target = config
233+
.target
234+
.clone()
235+
.or_else(|| cargo_config_build_target(cargo_toml))
236+
.or_else(|| rustc_discover_host_triple(cargo_toml));
237+
237238
let mut meta = MetadataCommand::new();
238239
meta.cargo_path(toolchain::cargo());
239240
meta.manifest_path(cargo_toml.to_path_buf());
@@ -249,16 +250,8 @@ impl CargoWorkspace {
249250
meta.features(CargoOpt::SomeFeatures(config.features.clone()));
250251
}
251252
}
252-
if let Some(parent) = cargo_toml.parent() {
253-
meta.current_dir(parent.to_path_buf());
254-
}
255-
let target = if let Some(target) = &config.target {
256-
Some(target.clone())
257-
} else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
258-
stdout
259-
} else {
260-
rustc_discover_host_triple(cargo_toml)
261-
};
253+
meta.current_dir(cargo_toml.parent().as_os_str());
254+
262255
if let Some(target) = target {
263256
meta.other_options(vec![String::from("--filter-platform"), target]);
264257
}
@@ -269,21 +262,7 @@ impl CargoWorkspace {
269262
progress("metadata".to_string());
270263

271264
let meta = meta.exec().with_context(|| {
272-
let cwd: Option<AbsPathBuf> =
273-
std::env::current_dir().ok().and_then(|p| p.try_into().ok());
274-
275-
let workdir = cargo_toml
276-
.parent()
277-
.map(|p| p.to_path_buf())
278-
.or(cwd)
279-
.map(|dir| format!(" in `{}`", dir.display()))
280-
.unwrap_or_default();
281-
282-
format!(
283-
"Failed to run `cargo metadata --manifest-path {}`{}",
284-
cargo_toml.display(),
285-
workdir
286-
)
265+
format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display(),)
287266
})?;
288267

289268
Ok(meta)
@@ -312,7 +291,7 @@ impl CargoWorkspace {
312291
id: id.repr.clone(),
313292
name: name.clone(),
314293
version: version.clone(),
315-
manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)),
294+
manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
316295
targets: Vec::new(),
317296
is_member,
318297
edition,
@@ -376,7 +355,7 @@ impl CargoWorkspace {
376355
}
377356

378357
pub fn from_cargo_metadata3(
379-
cargo_toml: &AbsPath,
358+
cargo_toml: &ManifestPath,
380359
config: &CargoConfig,
381360
progress: &dyn Fn(String),
382361
) -> Result<CargoWorkspace> {
@@ -412,9 +391,9 @@ impl CargoWorkspace {
412391
}
413392
}
414393

415-
fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
394+
fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> {
416395
let mut rustc = Command::new(toolchain::rustc());
417-
rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
396+
rustc.current_dir(cargo_toml.parent()).arg("-vV");
418397
log::debug!("Discovering host platform by {:?}", rustc);
419398
match utf8_stdout(rustc) {
420399
Ok(stdout) => {
@@ -435,10 +414,10 @@ fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
435414
}
436415
}
437416

438-
fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
417+
fn cargo_config_build_target(cargo_toml: &ManifestPath) -> Option<String> {
439418
let mut cargo_config = Command::new(toolchain::cargo());
440419
cargo_config
441-
.current_dir(cargo_toml.parent().unwrap())
420+
.current_dir(cargo_toml.parent())
442421
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
443422
.env("RUSTC_BOOTSTRAP", "1");
444423
// if successful we receive `build.target = "target-triple"`

crates/project_model/src/lib.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! procedural macros).
1616
//! * Lowering of concrete model to a [`base_db::CrateGraph`]
1717
18+
mod manifest_path;
1819
mod cargo_workspace;
1920
mod cfg_flag;
2021
mod project_json;
@@ -24,12 +25,13 @@ mod rustc_cfg;
2425
mod build_scripts;
2526

2627
use std::{
28+
convert::{TryFrom, TryInto},
2729
fs::{self, read_dir, ReadDir},
2830
io,
2931
process::Command,
3032
};
3133

32-
use anyhow::{bail, Context, Result};
34+
use anyhow::{bail, format_err, Context, Result};
3335
use paths::{AbsPath, AbsPathBuf};
3436
use rustc_hash::FxHashSet;
3537

@@ -39,6 +41,7 @@ pub use crate::{
3941
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target,
4042
TargetData, TargetKind,
4143
},
44+
manifest_path::ManifestPath,
4245
project_json::{ProjectJson, ProjectJsonData},
4346
sysroot::Sysroot,
4447
workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
@@ -48,12 +51,14 @@ pub use proc_macro_api::ProcMacroClient;
4851

4952
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
5053
pub enum ProjectManifest {
51-
ProjectJson(AbsPathBuf),
52-
CargoToml(AbsPathBuf),
54+
ProjectJson(ManifestPath),
55+
CargoToml(ManifestPath),
5356
}
5457

5558
impl ProjectManifest {
5659
pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> {
60+
let path = ManifestPath::try_from(path)
61+
.map_err(|path| format_err!("bad manifest path: {}", path.display()))?;
5762
if path.file_name().unwrap_or_default() == "rust-project.json" {
5863
return Ok(ProjectManifest::ProjectJson(path));
5964
}
@@ -83,38 +88,43 @@ impl ProjectManifest {
8388
return find_cargo_toml(path)
8489
.map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect());
8590

86-
fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> {
91+
fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<ManifestPath>> {
8792
match find_in_parent_dirs(path, "Cargo.toml") {
8893
Some(it) => Ok(vec![it]),
8994
None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
9095
}
9196
}
9297

93-
fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> {
98+
fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<ManifestPath> {
9499
if path.file_name().unwrap_or_default() == target_file_name {
95-
return Some(path.to_path_buf());
100+
if let Ok(manifest) = ManifestPath::try_from(path.to_path_buf()) {
101+
return Some(manifest);
102+
}
96103
}
97104

98105
let mut curr = Some(path);
99106

100107
while let Some(path) = curr {
101108
let candidate = path.join(target_file_name);
102109
if fs::metadata(&candidate).is_ok() {
103-
return Some(candidate);
110+
if let Ok(manifest) = ManifestPath::try_from(candidate) {
111+
return Some(manifest);
112+
}
104113
}
105114
curr = path.parent();
106115
}
107116

108117
None
109118
}
110119

111-
fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> {
120+
fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<ManifestPath> {
112121
// Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
113122
entities
114123
.filter_map(Result::ok)
115124
.map(|it| it.path().join("Cargo.toml"))
116125
.filter(|it| it.exists())
117126
.map(AbsPathBuf::assert)
127+
.filter_map(|it| it.try_into().ok())
118128
.collect()
119129
}
120130
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! See [`ManifestPath`].
2+
use std::{convert::TryFrom, ops, path::Path};
3+
4+
use paths::{AbsPath, AbsPathBuf};
5+
6+
/// More or less [`AbsPathBuf`] with non-None parent.
7+
///
8+
/// We use it to store path to Cargo.toml, as we frequently use the parent dir
9+
/// as a working directory to spawn various commands, and its nice to not have
10+
/// to `.unwrap()` everywhere.
11+
///
12+
/// This could have been named `AbsNonRootPathBuf`, as we don't enforce that
13+
/// this stores manifest files in particular, but we only use this for manifests
14+
/// at the moment in practice.
15+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
16+
pub struct ManifestPath {
17+
file: AbsPathBuf,
18+
}
19+
20+
impl TryFrom<AbsPathBuf> for ManifestPath {
21+
type Error = AbsPathBuf;
22+
23+
fn try_from(file: AbsPathBuf) -> Result<Self, Self::Error> {
24+
if file.parent().is_none() {
25+
Err(file)
26+
} else {
27+
Ok(ManifestPath { file })
28+
}
29+
}
30+
}
31+
32+
impl ManifestPath {
33+
// Shadow `parent` from `Deref`.
34+
pub fn parent(&self) -> &AbsPath {
35+
self.file.parent().unwrap()
36+
}
37+
}
38+
39+
impl ops::Deref for ManifestPath {
40+
type Target = AbsPath;
41+
42+
fn deref(&self) -> &Self::Target {
43+
&*self.file
44+
}
45+
}
46+
47+
impl AsRef<Path> for ManifestPath {
48+
fn as_ref(&self) -> &Path {
49+
self.file.as_ref()
50+
}
51+
}

crates/project_model/src/rustc_cfg.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
use std::process::Command;
44

55
use anyhow::Result;
6-
use paths::AbsPath;
76

8-
use crate::{cfg_flag::CfgFlag, utf8_stdout};
7+
use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
98

10-
pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> {
9+
pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Vec<CfgFlag> {
1110
let _p = profile::span("rustc_cfg::get");
1211
let mut res = Vec::with_capacity(6 * 2 + 1);
1312

@@ -27,12 +26,12 @@ pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<Cfg
2726
res
2827
}
2928

30-
fn get_rust_cfgs(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Result<String> {
29+
fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Result<String> {
3130
let cargo_rust_cfgs = match cargo_toml {
3231
Some(cargo_toml) => {
3332
let mut cargo_config = Command::new(toolchain::cargo());
3433
cargo_config
35-
.current_dir(cargo_toml.parent().unwrap())
34+
.current_dir(cargo_toml.parent())
3635
.args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
3736
.env("RUSTC_BOOTSTRAP", "1");
3837
if let Some(target) = target {

0 commit comments

Comments
 (0)