Use downcasting for CargoTomlNotFoundError

This commit is contained in:
Wilco Kusee 2020-01-08 14:04:47 +01:00
parent e7bb82c3a4
commit 003620f0d6
No known key found for this signature in database
GPG Key ID: D5B2BB5CDC3334BC
6 changed files with 48 additions and 97 deletions

View File

@ -10,10 +10,7 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit};
pub use crate::{
cancellation::Canceled,
input::{
CrateGraph, CrateId, Dependency, Edition, Env, FileId, ParseEditionError, SourceRoot,
SourceRootId,
},
input::{CrateGraph, CrateId, Dependency, Edition, Env, FileId, SourceRoot, SourceRootId},
};
pub use relative_path::{RelativePath, RelativePathBuf};
pub use salsa;

View File

@ -13,7 +13,6 @@ use lsp_types::{ClientCapabilities, NumberOrString};
use ra_cargo_watch::{CheckOptions, CheckTask};
use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
use ra_prof::profile;
use ra_project_model::WorkspaceError;
use ra_vfs::{VfsTask, Watch};
use relative_path::RelativePathBuf;
use rustc_hash::FxHashSet;
@ -92,7 +91,8 @@ pub fn main_loop(
Ok(workspace) => loaded_workspaces.push(workspace),
Err(e) => {
log::error!("loading workspace failed: {}", e);
if let WorkspaceError::CargoTomlNotFound(_) = e {
if let Some(ra_project_model::CargoTomlNotFoundError(_)) = e.downcast_ref()
{
if !feature_flags.get("notifications.cargo-toml-not-found") {
continue;
}

View File

@ -8,7 +8,7 @@ use ra_db::Edition;
use rustc_hash::FxHashMap;
use serde::Deserialize;
use crate::WorkspaceError;
use crate::Result;
/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
@ -156,7 +156,7 @@ impl CargoWorkspace {
pub fn from_cargo_metadata(
cargo_toml: &Path,
cargo_features: &CargoFeatures,
) -> Result<CargoWorkspace, WorkspaceError> {
) -> Result<CargoWorkspace> {
let mut meta = MetadataCommand::new();
meta.manifest_path(cargo_toml);
if cargo_features.all_features {
@ -171,7 +171,7 @@ impl CargoWorkspace {
if let Some(parent) = cargo_toml.parent() {
meta.current_dir(parent);
}
let meta = meta.exec().map_err(|e| WorkspaceError::CargoMetadataFailed(e))?;
let meta = meta.exec().map_err(|e| format!("cargo metadata failed: {}", e))?;
let mut pkg_by_id = FxHashMap::default();
let mut packages = Arena::default();
let mut targets = Arena::default();

View File

@ -3,9 +3,9 @@
mod cargo_workspace;
mod json_project;
mod sysroot;
mod workspace_error;
use std::{
error::Error,
fs::File,
io::BufReader,
path::{Path, PathBuf},
@ -21,9 +21,27 @@ pub use crate::{
cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind},
json_project::JsonProject,
sysroot::Sysroot,
workspace_error::WorkspaceError,
};
pub type Result<T> = ::std::result::Result<T, Box<dyn Error + Send + Sync>>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CargoTomlNotFoundError(pub PathBuf);
impl std::fmt::Display for CargoTomlNotFoundError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "can't find Cargo.toml at {}", self.0.display())
}
}
impl std::fmt::Debug for CargoTomlNotFoundError {
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 {}
#[derive(Debug, Clone)]
pub enum ProjectWorkspace {
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
@ -58,10 +76,7 @@ impl PackageRoot {
}
impl ProjectWorkspace {
pub fn discover(
path: &Path,
cargo_features: &CargoFeatures,
) -> Result<ProjectWorkspace, WorkspaceError> {
pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> {
ProjectWorkspace::discover_with_sysroot(path, true, cargo_features)
}
@ -69,16 +84,12 @@ impl ProjectWorkspace {
path: &Path,
with_sysroot: bool,
cargo_features: &CargoFeatures,
) -> Result<ProjectWorkspace, WorkspaceError> {
) -> Result<ProjectWorkspace> {
match find_rust_project_json(path) {
Some(json_path) => {
let file =
File::open(json_path).map_err(|err| WorkspaceError::OpenWorkspaceError(err))?;
let file = File::open(json_path)?;
let reader = BufReader::new(file);
Ok(ProjectWorkspace::Json {
project: from_reader(reader)
.map_err(|err| WorkspaceError::ReadWorkspaceError(err))?,
})
Ok(ProjectWorkspace::Json { project: from_reader(reader)? })
}
None => {
let cargo_toml = find_cargo_toml(path)?;
@ -355,7 +366,7 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
None
}
fn find_cargo_toml(path: &Path) -> Result<PathBuf, WorkspaceError> {
fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
if path.ends_with("Cargo.toml") {
return Ok(path.to_path_buf());
}
@ -367,7 +378,7 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf, WorkspaceError> {
}
curr = path.parent();
}
Err(WorkspaceError::CargoTomlNotFound(path.to_path_buf()))
Err(Box::new(CargoTomlNotFoundError(path.to_path_buf())))
}
pub fn get_rustc_cfg_options() -> CfgOptions {
@ -381,16 +392,13 @@ pub fn get_rustc_cfg_options() -> CfgOptions {
}
}
match (|| -> Result<_, WorkspaceError> {
match (|| -> Result<_> {
// `cfg(test)` and `cfg(debug_assertion)` are handled outside, so we suppress them here.
let output = Command::new("rustc")
.args(&["--print", "cfg", "-O"])
.output()
.map_err(|err| WorkspaceError::RustcError(err))?;
let output = Command::new("rustc").args(&["--print", "cfg", "-O"]).output()?;
if !output.status.success() {
Err(WorkspaceError::RustcCfgError)?;
Err("failed to get rustc cfgs")?;
}
Ok(String::from_utf8(output.stdout).map_err(|err| WorkspaceError::RustcOutputError(err))?)
Ok(String::from_utf8(output.stdout)?)
})() {
Ok(rustc_cfgs) => {
for line in rustc_cfgs.lines() {

View File

@ -8,7 +8,7 @@ use std::{
use ra_arena::{impl_arena_id, Arena, RawId};
use crate::WorkspaceError;
use crate::Result;
#[derive(Default, Debug, Clone)]
pub struct Sysroot {
@ -47,11 +47,16 @@ impl Sysroot {
self.crates.iter().map(|(id, _data)| id)
}
pub fn discover(cargo_toml: &Path) -> Result<Sysroot, WorkspaceError> {
pub fn discover(cargo_toml: &Path) -> Result<Sysroot> {
let src = try_find_src_path(cargo_toml)?;
if !src.exists() {
return Err(WorkspaceError::NoStdLib(src));
Err(format!(
"can't load standard library from sysroot\n\
{:?}\n\
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
src,
))?;
}
let mut sysroot = Sysroot { crates: Arena::default() };
@ -85,7 +90,7 @@ impl Sysroot {
}
}
fn try_find_src_path(cargo_toml: &Path) -> Result<PathBuf, WorkspaceError> {
fn try_find_src_path(cargo_toml: &Path) -> Result<PathBuf> {
if let Ok(path) = env::var("RUST_SRC_PATH") {
return Ok(path.into());
}
@ -93,13 +98,11 @@ fn try_find_src_path(cargo_toml: &Path) -> Result<PathBuf, WorkspaceError> {
let rustc_output = Command::new("rustc")
.current_dir(cargo_toml.parent().unwrap())
.args(&["--print", "sysroot"])
.output()
.map_err(|err| WorkspaceError::RustcError(err))?;
.output()?;
if !rustc_output.status.success() {
Err(WorkspaceError::SysrootNotFound)?;
Err("failed to locate sysroot")?;
}
let stdout = String::from_utf8(rustc_output.stdout)
.map_err(|err| WorkspaceError::RustcOutputError(err))?;
let stdout = String::from_utf8(rustc_output.stdout)?;
let sysroot_path = Path::new(stdout.trim());
Ok(sysroot_path.join("lib/rustlib/src/rust/src"))
}

View File

@ -1,57 +0,0 @@
//! Workspace-related errors
use std::{error::Error, fmt, io, path::PathBuf, string::FromUtf8Error};
use ra_db::ParseEditionError;
#[derive(Debug)]
pub enum WorkspaceError {
CargoMetadataFailed(cargo_metadata::Error),
CargoTomlNotFound(PathBuf),
NoStdLib(PathBuf),
OpenWorkspaceError(io::Error),
ParseEditionError(ParseEditionError),
ReadWorkspaceError(serde_json::Error),
RustcCfgError,
RustcError(io::Error),
RustcOutputError(FromUtf8Error),
SysrootNotFound,
}
impl fmt::Display for WorkspaceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OpenWorkspaceError(err) | Self::RustcError(err) => write!(f, "{}", err),
Self::ParseEditionError(err) => write!(f, "{}", err),
Self::ReadWorkspaceError(err) => write!(f, "{}", err),
Self::RustcOutputError(err) => write!(f, "{}", err),
Self::CargoMetadataFailed(err) => write!(f, "cargo metadata failed: {}", err),
Self::RustcCfgError => write!(f, "failed to get rustc cfgs"),
Self::SysrootNotFound => write!(f, "failed to locate sysroot"),
Self::CargoTomlNotFound(path) => {
write!(f, "can't find Cargo.toml at {}", path.display())
}
Self::NoStdLib(sysroot) => write!(
f,
"can't load standard library from sysroot\n\
{:?}\n\
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
sysroot,
),
}
}
}
impl From<ParseEditionError> for WorkspaceError {
fn from(err: ParseEditionError) -> Self {
Self::ParseEditionError(err.into())
}
}
impl From<cargo_metadata::Error> for WorkspaceError {
fn from(err: cargo_metadata::Error) -> Self {
Self::CargoMetadataFailed(err.into())
}
}
impl Error for WorkspaceError {}