-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Find cargo toml up the fs #3309
Changes from 6 commits
34e3ef6
39bd3b2
f1b7349
9391b1c
f9f8edf
12b595e
e15424c
b9fbb3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ mod sysroot; | |
|
||
use std::{ | ||
error::Error, | ||
fs::File, | ||
fs::{read_dir, File, ReadDir}, | ||
io::BufReader, | ||
path::{Path, PathBuf}, | ||
process::Command, | ||
|
@@ -25,15 +25,35 @@ pub use crate::{ | |
}; | ||
|
||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
pub struct CargoTomlNotFoundError(pub PathBuf); | ||
pub struct CargoTomlNoneFoundError(pub PathBuf); | ||
|
||
impl std::fmt::Display for CargoTomlNotFoundError { | ||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
pub struct CargoTomlMultipleValidFoundError(pub Vec<PathBuf>); | ||
|
||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
pub struct CargoTomlSearchFileSystemError(pub PathBuf, pub String); | ||
|
||
impl std::fmt::Display for CargoTomlNoneFoundError { | ||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(fmt, "can't find Cargo.toml at {}", self.0.display()) | ||
} | ||
} | ||
|
||
impl Error for CargoTomlNotFoundError {} | ||
impl std::fmt::Display for CargoTomlMultipleValidFoundError { | ||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(fmt, "found multiple valid Cargo.toml files {:?}", self.0) | ||
} | ||
} | ||
|
||
impl std::fmt::Display for CargoTomlSearchFileSystemError { | ||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(fmt, "a filesystem error occurred while searching for Cargo.toml: {}", self.1) | ||
} | ||
} | ||
|
||
impl Error for CargoTomlNoneFoundError {} | ||
impl Error for CargoTomlMultipleValidFoundError {} | ||
impl Error for CargoTomlSearchFileSystemError {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hope this method of grouping is acceptable? Group related structs and impls together. I don't have a strong preference, I can more them around if that is preferred. :) |
||
|
||
#[derive(Debug, Clone)] | ||
pub enum ProjectWorkspace { | ||
|
@@ -406,19 +426,53 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> { | |
None | ||
} | ||
|
||
fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | ||
if path.ends_with("Cargo.toml") { | ||
return Ok(path.to_path_buf()); | ||
} | ||
fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> { | ||
let mut curr = Some(path); | ||
while let Some(path) = curr { | ||
let candidate = path.join("Cargo.toml"); | ||
if candidate.exists() { | ||
return Ok(candidate); | ||
return Some(candidate); | ||
} | ||
curr = path.parent(); | ||
} | ||
Err(CargoTomlNotFoundError(path.to_path_buf()).into()) | ||
|
||
None | ||
} | ||
|
||
fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> { | ||
// Only one level down to avoid cycles the easy way and stop a runaway scan with large projects | ||
let mut valid_canditates = vec![]; | ||
for entity in entities.filter_map(Result::ok) { | ||
let candidate = entity.path().join("Cargo.toml"); | ||
if candidate.exists() { | ||
valid_canditates.push(candidate) | ||
} | ||
} | ||
valid_canditates | ||
} | ||
|
||
fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | ||
let path_as_buf = path.to_path_buf(); | ||
|
||
if path.ends_with("Cargo.toml") { | ||
return Ok(path.to_path_buf()); | ||
} | ||
|
||
if let Some(p) = find_cargo_toml_in_parent_dir(path) { | ||
return Ok(p); | ||
} | ||
|
||
let entities = match read_dir(path) { | ||
Ok(entities) => entities, | ||
Err(e) => return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into()), | ||
}; | ||
|
||
let mut valid_canditates = find_cargo_toml_in_child_dir(entities); | ||
match valid_canditates.len() { | ||
1 => Ok(valid_canditates.remove(0)), | ||
0 => Err(CargoTomlNoneFoundError(path_as_buf).into()), | ||
_ => Err(CargoTomlMultipleValidFoundError(valid_canditates).into()), | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the naming is confusing... Let's do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you might have meant this anyway but just mentioning that I prefixed with find_cargo_toml_... because these functions are in a fairly "large" file so a new reader might wonder - find what? |
||
pub fn get_rustc_cfg_options() -> CfgOptions { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went this route to enumerate the possibilities, could also have been one error like:
However I don't THINK this is "rusty" or a common practice in general nor in this codebase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's stick with a single error type here