From 154cb8243b4212fddf73b3b3c48b5f5e8a712876 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 24 Jun 2020 13:34:24 +0200 Subject: Be more explicit about absolute paths at various places --- crates/ra_project_model/src/cargo_workspace.rs | 42 +++++++++++---------- crates/ra_project_model/src/lib.rs | 51 +++++++++++++------------- crates/ra_project_model/src/sysroot.rs | 23 ++++++------ 3 files changed, 58 insertions(+), 58 deletions(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 4b7444039..8ce63ab3c 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -1,14 +1,10 @@ //! FIXME: write short doc here -use std::{ - ffi::OsStr, - ops, - path::{Path, PathBuf}, - process::Command, -}; +use std::{ffi::OsStr, ops, path::Path, process::Command}; use anyhow::{Context, Result}; use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; +use paths::{AbsPath, AbsPathBuf}; use ra_arena::{Arena, Idx}; use ra_db::Edition; use rustc_hash::FxHashMap; @@ -20,11 +16,14 @@ use rustc_hash::FxHashMap; /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, /// while this knows about `Packages` & `Targets`: purely cargo-related /// concepts. +/// +/// We use absolute paths here, `cargo metadata` guarantees to always produce +/// abs paths. #[derive(Debug, Clone)] pub struct CargoWorkspace { packages: Arena, targets: Arena, - workspace_root: PathBuf, + workspace_root: AbsPathBuf, } impl ops::Index for CargoWorkspace { @@ -80,15 +79,15 @@ pub type Target = Idx; pub struct PackageData { pub version: String, pub name: String, - pub manifest: PathBuf, + pub manifest: AbsPathBuf, pub targets: Vec, pub is_member: bool, pub dependencies: Vec, pub edition: Edition, pub features: Vec, pub cfgs: Vec, - pub out_dir: Option, - pub proc_macro_dylib_path: Option, + pub out_dir: Option, + pub proc_macro_dylib_path: Option, } #[derive(Debug, Clone)] @@ -101,7 +100,7 @@ pub struct PackageDependency { pub struct TargetData { pub package: Package, pub name: String, - pub root: PathBuf, + pub root: AbsPathBuf, pub kind: TargetKind, pub is_proc_macro: bool, } @@ -135,7 +134,7 @@ impl TargetKind { } impl PackageData { - pub fn root(&self) -> &Path { + pub fn root(&self) -> &AbsPath { self.manifest.parent().unwrap() } } @@ -193,7 +192,7 @@ impl CargoWorkspace { let pkg = packages.alloc(PackageData { name, version: version.to_string(), - manifest: manifest_path, + manifest: AbsPathBuf::assert(manifest_path), targets: Vec::new(), is_member, edition, @@ -210,7 +209,7 @@ impl CargoWorkspace { let tgt = targets.alloc(TargetData { package: pkg, name: meta_tgt.name, - root: meta_tgt.src_path.clone(), + root: AbsPathBuf::assert(meta_tgt.src_path.clone()), kind: TargetKind::new(meta_tgt.kind.as_slice()), is_proc_macro, }); @@ -246,16 +245,17 @@ impl CargoWorkspace { packages[source].features.extend(node.features); } - Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root }) + let workspace_root = AbsPathBuf::assert(meta.workspace_root); + Ok(CargoWorkspace { packages, targets, workspace_root: workspace_root }) } pub fn packages<'a>(&'a self) -> impl Iterator + ExactSizeIterator + 'a { self.packages.iter().map(|(id, _pkg)| id) } - pub fn target_by_root(&self, root: &Path) -> Option { + pub fn target_by_root(&self, root: &AbsPath) -> Option { self.packages() - .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root)) + .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root)) .next() .copied() } @@ -279,8 +279,8 @@ impl CargoWorkspace { #[derive(Debug, Clone, Default)] pub struct ExternResources { - out_dirs: FxHashMap, - proc_dylib_paths: FxHashMap, + out_dirs: FxHashMap, + proc_dylib_paths: FxHashMap, cfgs: FxHashMap>, } @@ -308,6 +308,7 @@ pub fn load_extern_resources( if let Ok(message) = message { match message { Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { + let out_dir = AbsPathBuf::assert(out_dir); res.out_dirs.insert(package_id.clone(), out_dir); res.cfgs.insert(package_id, cfgs); } @@ -317,7 +318,8 @@ pub fn load_extern_resources( // Skip rmeta file if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) { - res.proc_dylib_paths.insert(package_id, filename.clone()); + let filename = AbsPathBuf::assert(filename.clone()); + res.proc_dylib_paths.insert(package_id, filename); } } } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fe3e81689..ac88532f0 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -7,11 +7,12 @@ mod sysroot; use std::{ fs::{read_dir, File, ReadDir}, io::{self, BufReader}, - path::{Path, PathBuf}, + path::Path, process::{Command, Output}, }; use anyhow::{bail, Context, Result}; +use paths::{AbsPath, AbsPathBuf}; use ra_cfg::CfgOptions; use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -29,7 +30,7 @@ pub enum ProjectWorkspace { /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, /// Project workspace was manually specified using a `rust-project.json` file. - Json { project: JsonProject, project_location: PathBuf }, + Json { project: JsonProject, project_location: AbsPathBuf }, } /// `PackageRoot` describes a package root folder. @@ -38,22 +39,22 @@ pub enum ProjectWorkspace { #[derive(Debug, Clone)] pub struct PackageRoot { /// Path to the root folder - path: PathBuf, + path: AbsPathBuf, /// Is a member of the current workspace is_member: bool, - out_dir: Option, + out_dir: Option, } impl PackageRoot { - pub fn new_member(path: PathBuf) -> PackageRoot { + pub fn new_member(path: AbsPathBuf) -> PackageRoot { Self { path, is_member: true, out_dir: None } } - pub fn new_non_member(path: PathBuf) -> PackageRoot { + pub fn new_non_member(path: AbsPathBuf) -> PackageRoot { Self { path, is_member: false, out_dir: None } } - pub fn path(&self) -> &Path { + pub fn path(&self) -> &AbsPath { &self.path } - pub fn out_dir(&self) -> Option<&Path> { + pub fn out_dir(&self) -> Option<&AbsPath> { self.out_dir.as_deref() } pub fn is_member(&self) -> bool { @@ -63,12 +64,12 @@ impl PackageRoot { #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectManifest { - ProjectJson(PathBuf), - CargoToml(PathBuf), + ProjectJson(AbsPathBuf), + CargoToml(AbsPathBuf), } impl ProjectManifest { - pub fn from_manifest_file(path: PathBuf) -> Result { + pub fn from_manifest_file(path: AbsPathBuf) -> Result { if path.ends_with("rust-project.json") { return Ok(ProjectManifest::ProjectJson(path)); } @@ -78,7 +79,7 @@ impl ProjectManifest { bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) } - pub fn discover_single(path: &Path) -> Result { + pub fn discover_single(path: &AbsPath) -> Result { let mut candidates = ProjectManifest::discover(path)?; let res = match candidates.pop() { None => bail!("no projects"), @@ -91,23 +92,23 @@ impl ProjectManifest { Ok(res) } - pub fn discover(path: &Path) -> io::Result> { + pub fn discover(path: &AbsPath) -> io::Result> { if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { return Ok(vec![ProjectManifest::ProjectJson(project_json)]); } return find_cargo_toml(path) .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); - fn find_cargo_toml(path: &Path) -> io::Result> { + fn find_cargo_toml(path: &AbsPath) -> io::Result> { match find_in_parent_dirs(path, "Cargo.toml") { Some(it) => Ok(vec![it]), None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), } } - fn find_in_parent_dirs(path: &Path, target_file_name: &str) -> Option { + fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option { if path.ends_with(target_file_name) { - return Some(path.to_owned()); + return Some(path.to_path_buf()); } let mut curr = Some(path); @@ -123,17 +124,18 @@ impl ProjectManifest { None } - fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec { + fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec { // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects entities .filter_map(Result::ok) .map(|it| it.path().join("Cargo.toml")) .filter(|it| it.exists()) + .map(AbsPathBuf::assert) .collect() } } - pub fn discover_all(paths: &[impl AsRef]) -> Vec { + pub fn discover_all(paths: &[impl AsRef]) -> Vec { let mut res = paths .iter() .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) @@ -158,15 +160,12 @@ impl ProjectWorkspace { format!("Failed to open json file {}", project_json.display()) })?; let reader = BufReader::new(file); - let project_location = match project_json.parent() { - Some(parent) => PathBuf::from(parent), - None => PathBuf::new(), - }; + let project_location = project_json.parent().unwrap().to_path_buf(); ProjectWorkspace::Json { project: from_reader(reader).with_context(|| { format!("Failed to deserialize json file {}", project_json.display()) })?, - project_location: project_location, + project_location, } } ProjectManifest::CargoToml(cargo_toml) => { @@ -218,13 +217,13 @@ impl ProjectWorkspace { } } - pub fn proc_macro_dylib_paths(&self) -> Vec { + pub fn proc_macro_dylib_paths(&self) -> Vec { match self { - ProjectWorkspace::Json { project, .. } => project + ProjectWorkspace::Json { project, project_location } => project .crates .iter() .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) - .cloned() + .map(|it| project_location.join(it)) .collect(), ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo .packages() diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index a8a196e64..943ff92df 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs @@ -1,15 +1,12 @@ //! FIXME: write short doc here -use std::{ - env, ops, - path::{Path, PathBuf}, - process::Command, -}; +use std::{convert::TryFrom, env, ops, path::Path, process::Command}; -use anyhow::{bail, Result}; +use anyhow::{bail, format_err, Result}; use ra_arena::{Arena, Idx}; use crate::output; +use paths::{AbsPath, AbsPathBuf}; #[derive(Default, Debug, Clone)] pub struct Sysroot { @@ -21,7 +18,7 @@ pub type SysrootCrate = Idx; #[derive(Debug, Clone)] pub struct SysrootCrateData { pub name: String, - pub root: PathBuf, + pub root: AbsPathBuf, pub deps: Vec, } @@ -53,7 +50,7 @@ impl Sysroot { self.crates.iter().map(|(id, _data)| id) } - pub fn discover(cargo_toml: &Path) -> Result { + pub fn discover(cargo_toml: &AbsPath) -> Result { let src = get_or_install_rust_src(cargo_toml)?; let mut sysroot = Sysroot { crates: Arena::default() }; for name in SYSROOT_CRATES.trim().lines() { @@ -86,16 +83,18 @@ impl Sysroot { } } -fn get_or_install_rust_src(cargo_toml: &Path) -> Result { +fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result { if let Ok(path) = env::var("RUST_SRC_PATH") { - return Ok(path.into()); + let path = AbsPathBuf::try_from(path.as_str()) + .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?; + return Ok(path); } let current_dir = cargo_toml.parent().unwrap(); let mut rustc = Command::new(ra_toolchain::rustc()); rustc.current_dir(current_dir).args(&["--print", "sysroot"]); let rustc_output = output(rustc)?; let stdout = String::from_utf8(rustc_output.stdout)?; - let sysroot_path = Path::new(stdout.trim()); + let sysroot_path = AbsPath::assert(Path::new(stdout.trim())); let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); if !src_path.exists() { @@ -116,7 +115,7 @@ fn get_or_install_rust_src(cargo_toml: &Path) -> Result { } impl SysrootCrateData { - pub fn root_dir(&self) -> &Path { + pub fn root_dir(&self) -> &AbsPath { self.root.parent().unwrap() } } -- cgit v1.2.3