From fcd615e4b76264b4fff7b5be454787bb6a4252ea Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 5 Feb 2019 23:10:49 +0100 Subject: Extract project model to separate crate --- crates/ra_lsp_server/Cargo.toml | 2 +- crates/ra_lsp_server/src/project_model.rs | 42 +---- .../src/project_model/cargo_workspace.rs | 171 --------------------- crates/ra_lsp_server/src/project_model/sysroot.rs | 137 ----------------- 4 files changed, 4 insertions(+), 348 deletions(-) delete mode 100644 crates/ra_lsp_server/src/project_model/cargo_workspace.rs delete mode 100644 crates/ra_lsp_server/src/project_model/sysroot.rs (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index bb92747f2..f46d77893 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -19,7 +19,6 @@ url_serde = "0.2.0" lsp-types = "0.55.0" walkdir = "2.2.7" im = "12.0.0" -cargo_metadata = "0.7.0" rustc-hash = "1.0" parking_lot = "0.7.0" @@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" } ra_arena = { path = "../ra_arena" } gen_lsp_server = { path = "../gen_lsp_server" } ra_vfs = { path = "../ra_vfs" } +ra_project_model = { path = "../ra_project_model" } [dev-dependencies] tempfile = "3" diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index fd5875a0a..6800eb138 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -1,34 +1,13 @@ -mod cargo_workspace; -mod sysroot; +use std::path::PathBuf; -use std::path::{Path, PathBuf}; - -use failure::bail; use thread_worker::{WorkerHandle, Worker}; use crate::Result; -pub use crate::project_model::{ - cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, - sysroot::Sysroot, +pub use ra_project_model::{ + ProjectWorkspace, CargoWorkspace, Package, Target, TargetKind, Sysroot, }; -#[derive(Debug, Clone)] -pub struct ProjectWorkspace { - pub(crate) cargo: CargoWorkspace, - pub(crate) sysroot: Sysroot, -} - -impl ProjectWorkspace { - pub fn discover(path: &Path) -> Result { - let cargo_toml = find_cargo_toml(path)?; - let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; - let sysroot = Sysroot::discover(&cargo_toml)?; - let res = ProjectWorkspace { cargo, sysroot }; - Ok(res) - } -} - pub fn workspace_loader() -> (Worker>, WorkerHandle) { thread_worker::spawn::, _>( "workspace loader", @@ -42,18 +21,3 @@ pub fn workspace_loader() -> (Worker>, WorkerH }, ) } - -fn find_cargo_toml(path: &Path) -> Result { - if path.ends_with("Cargo.toml") { - return Ok(path.to_path_buf()); - } - let mut curr = Some(path); - while let Some(path) = curr { - let candidate = path.join("Cargo.toml"); - if candidate.exists() { - return Ok(candidate); - } - curr = path.parent(); - } - bail!("can't find Cargo.toml at {}", path.display()) -} diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs deleted file mode 100644 index 3b76389d2..000000000 --- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::path::{Path, PathBuf}; - -use cargo_metadata::{MetadataCommand, CargoOpt}; -use ra_syntax::SmolStr; -use ra_arena::{Arena, RawId, impl_arena_id}; -use rustc_hash::FxHashMap; -use failure::format_err; - -use crate::Result; - -/// `CargoWorksapce` represents the logical structure of, well, a Cargo -/// workspace. It pretty closely mirrors `cargo metadata` output. -/// -/// Note that internally, rust analyzer uses a differnet structure: -/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, -/// while this knows about `Pacakges` & `Targets`: purely cargo-related -/// concepts. -#[derive(Debug, Clone)] -pub struct CargoWorkspace { - packages: Arena, - targets: Arena, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Package(RawId); -impl_arena_id!(Package); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Target(RawId); -impl_arena_id!(Target); - -#[derive(Debug, Clone)] -struct PackageData { - name: SmolStr, - manifest: PathBuf, - targets: Vec, - is_member: bool, - dependencies: Vec, -} - -#[derive(Debug, Clone)] -pub struct PackageDependency { - pub pkg: Package, - pub name: SmolStr, -} - -#[derive(Debug, Clone)] -struct TargetData { - pkg: Package, - name: SmolStr, - root: PathBuf, - kind: TargetKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TargetKind { - Bin, - Lib, - Example, - Test, - Bench, - Other, -} - -impl TargetKind { - fn new(kinds: &[String]) -> TargetKind { - for kind in kinds { - return match kind.as_str() { - "bin" => TargetKind::Bin, - "test" => TargetKind::Test, - "bench" => TargetKind::Bench, - "example" => TargetKind::Example, - _ if kind.contains("lib") => TargetKind::Lib, - _ => continue, - }; - } - TargetKind::Other - } -} - -impl Package { - pub fn name(self, ws: &CargoWorkspace) -> &str { - ws.packages[self].name.as_str() - } - pub fn root(self, ws: &CargoWorkspace) -> &Path { - ws.packages[self].manifest.parent().unwrap() - } - pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { - ws.packages[self].targets.iter().cloned() - } - #[allow(unused)] - pub fn is_member(self, ws: &CargoWorkspace) -> bool { - ws.packages[self].is_member - } - pub fn dependencies<'a>( - self, - ws: &'a CargoWorkspace, - ) -> impl Iterator + 'a { - ws.packages[self].dependencies.iter() - } -} - -impl Target { - pub fn package(self, ws: &CargoWorkspace) -> Package { - ws.targets[self].pkg - } - pub fn name(self, ws: &CargoWorkspace) -> &str { - ws.targets[self].name.as_str() - } - pub fn root(self, ws: &CargoWorkspace) -> &Path { - ws.targets[self].root.as_path() - } - pub fn kind(self, ws: &CargoWorkspace) -> TargetKind { - ws.targets[self].kind - } -} - -impl CargoWorkspace { - pub fn from_cargo_metadata(cargo_toml: &Path) -> Result { - let mut meta = MetadataCommand::new(); - meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); - if let Some(parent) = cargo_toml.parent() { - meta.current_dir(parent); - } - let meta = meta.exec().map_err(|e| format_err!("cargo metadata failed: {}", e))?; - let mut pkg_by_id = FxHashMap::default(); - let mut packages = Arena::default(); - let mut targets = Arena::default(); - - let ws_members = &meta.workspace_members; - - for meta_pkg in meta.packages { - let is_member = ws_members.contains(&meta_pkg.id); - let pkg = packages.alloc(PackageData { - name: meta_pkg.name.into(), - manifest: meta_pkg.manifest_path.clone(), - targets: Vec::new(), - is_member, - dependencies: Vec::new(), - }); - let pkg_data = &mut packages[pkg]; - pkg_by_id.insert(meta_pkg.id.clone(), pkg); - for meta_tgt in meta_pkg.targets { - let tgt = targets.alloc(TargetData { - pkg, - name: meta_tgt.name.into(), - root: meta_tgt.src_path.clone(), - kind: TargetKind::new(meta_tgt.kind.as_slice()), - }); - pkg_data.targets.push(tgt); - } - } - let resolve = meta.resolve.expect("metadata executed with deps"); - for node in resolve.nodes { - let source = pkg_by_id[&node.id]; - for dep_node in node.deps { - let dep = - PackageDependency { name: dep_node.name.into(), pkg: pkg_by_id[&dep_node.pkg] }; - packages[source].dependencies.push(dep); - } - } - - Ok(CargoWorkspace { packages, targets }) - } - pub fn packages<'a>(&'a self) -> impl Iterator + 'a { - self.packages.iter().map(|(id, _pkg)| id) - } - pub fn target_by_root(&self, root: &Path) -> Option { - self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() - } -} diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs deleted file mode 100644 index 49210ac7a..000000000 --- a/crates/ra_lsp_server/src/project_model/sysroot.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::{ - path::{Path, PathBuf}, - process::Command, -}; - -use ra_syntax::SmolStr; -use ra_arena::{Arena, RawId, impl_arena_id}; - -use crate::Result; - -#[derive(Debug, Clone)] -pub struct Sysroot { - crates: Arena, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SysrootCrate(RawId); -impl_arena_id!(SysrootCrate); - -#[derive(Debug, Clone)] -struct SysrootCrateData { - name: SmolStr, - root: PathBuf, - deps: Vec, -} - -impl Sysroot { - pub(crate) fn std(&self) -> Option { - self.by_name("std") - } - - pub(crate) fn crates<'a>(&'a self) -> impl Iterator + 'a { - self.crates.iter().map(|(id, _data)| id) - } - - pub(super) fn discover(cargo_toml: &Path) -> Result { - let rustc_output = Command::new("rustc") - .current_dir(cargo_toml.parent().unwrap()) - .args(&["--print", "sysroot"]) - .output()?; - if !rustc_output.status.success() { - failure::bail!("failed to locate sysroot") - } - let stdout = String::from_utf8(rustc_output.stdout)?; - let sysroot_path = Path::new(stdout.trim()); - let src = sysroot_path.join("lib/rustlib/src/rust/src"); - if !src.exists() { - failure::bail!( - "can't load standard library from sysroot\n\ - {:?}\n\ - try running `rustup component add rust-src`", - src, - ); - } - - let mut sysroot = Sysroot { crates: Arena::default() }; - for name in SYSROOT_CRATES.trim().lines() { - let root = src.join(format!("lib{}", name)).join("lib.rs"); - if root.exists() { - sysroot.crates.alloc(SysrootCrateData { - name: name.into(), - root, - deps: Vec::new(), - }); - } - } - if let Some(std) = sysroot.std() { - for dep in STD_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[std].deps.push(dep) - } - } - } - Ok(sysroot) - } - - fn by_name(&self, name: &str) -> Option { - self.crates.iter().find(|(_id, data)| data.name == name).map(|(id, _data)| id) - } -} - -impl SysrootCrate { - pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { - &sysroot.crates[self].name - } - pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { - sysroot.crates[self].root.as_path() - } - pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { - self.root(sysroot).parent().unwrap() - } - pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator + 'a { - sysroot.crates[self].deps.iter().map(|&it| it) - } -} - -const SYSROOT_CRATES: &str = " -std -core -alloc -collections -libc -panic_unwind -proc_macro -rustc_unicode -std_unicode -test -alloc_jemalloc -alloc_system -compiler_builtins -getopts -panic_unwind -panic_abort -rand -term -unwind -build_helper -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -syntax"; - -const STD_DEPS: &str = " -alloc -alloc_jemalloc -alloc_system -core -panic_abort -rand -compiler_builtins -unwind -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -build_helper"; -- cgit v1.2.3