//! In rust-analyzer, we maintain a strict separation between pure abstract //! semantic project model and a concrete model of a particular build system. //! //! Pure model is represented by the [`base_db::CrateGraph`] from another crate. //! //! In this crate, we are concerned with "real world" project models. //! //! Specifically, here we have a representation for a Cargo project //! ([`CargoWorkspace`]) and for manually specified layout ([`ProjectJson`]). //! //! Roughly, the things we do here are: //! //! * Project discovery (where's the relevant Cargo.toml for the current dir). //! * Custom build steps (`build.rs` code generation and compilation of //! procedural macros). //! * Lowering of concrete model to a [`base_db::CrateGraph`] mod build_dependencies; mod cargo_workspace; mod env; mod manifest_path; pub mod project_json; mod rustc_cfg; mod sysroot; pub mod target_data_layout; mod workspace; #[cfg(test)] mod tests; use std::{ fmt, fs::{self, read_dir, ReadDir}, io, process::Command, }; use anyhow::{bail, format_err, Context}; use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::FxHashSet; pub use crate::{ build_dependencies::WorkspaceBuildScripts, cargo_workspace::{ CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency, RustLibSource, Target, TargetData, TargetKind, }, manifest_path::ManifestPath, project_json::{ProjectJson, ProjectJsonData}, sysroot::Sysroot, workspace::{FileLoader, PackageRoot, ProjectWorkspace, ProjectWorkspaceKind}, }; pub use cargo_metadata::Metadata; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProjectJsonFromCommand { /// The data describing this project, such as its dependencies. pub data: ProjectJsonData, /// The build system specific file that describes this project, /// such as a `my-project/BUCK` file. pub buildfile: AbsPathBuf, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectManifest { ProjectJson(ManifestPath), CargoToml(ManifestPath), CargoScript(ManifestPath), } impl ProjectManifest { pub fn from_manifest_file(path: AbsPathBuf) -> anyhow::Result { let path = ManifestPath::try_from(path) .map_err(|path| format_err!("bad manifest path: {path}"))?; if path.file_name().unwrap_or_default() == "rust-project.json" { return Ok(ProjectManifest::ProjectJson(path)); } if path.file_name().unwrap_or_default() == ".rust-project.json" { return Ok(ProjectManifest::ProjectJson(path)); } if path.file_name().unwrap_or_default() == "Cargo.toml" { return Ok(ProjectManifest::CargoToml(path)); } if path.extension().unwrap_or_default() == "rs" { return Ok(ProjectManifest::CargoScript(path)); } bail!("project root must point to a Cargo.toml, rust-project.json or