More direct CargoWorkspace

This commit is contained in:
Aleksey Kladov 2020-03-19 17:53:31 +01:00
parent d013a05fee
commit 516fe293a8
3 changed files with 64 additions and 87 deletions

View file

@ -1,6 +1,9 @@
//! FIXME: write short doc here //! FIXME: write short doc here
use std::path::{Path, PathBuf}; use std::{
ops,
path::{Path, PathBuf},
};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId}; use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId};
@ -24,6 +27,20 @@ pub struct CargoWorkspace {
workspace_root: PathBuf, workspace_root: PathBuf,
} }
impl ops::Index<Package> for CargoWorkspace {
type Output = PackageData;
fn index(&self, index: Package) -> &PackageData {
&self.packages[index]
}
}
impl ops::Index<Target> for CargoWorkspace {
type Output = TargetData;
fn index(&self, index: Target) -> &TargetData {
&self.targets[index]
}
}
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] #[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase", default)] #[serde(rename_all = "camelCase", default)]
pub struct CargoFeatures { pub struct CargoFeatures {
@ -61,15 +78,15 @@ pub struct Target(RawId);
impl_arena_id!(Target); impl_arena_id!(Target);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct PackageData { pub struct PackageData {
name: String, pub name: String,
manifest: PathBuf, pub manifest: PathBuf,
targets: Vec<Target>, pub targets: Vec<Target>,
is_member: bool, pub is_member: bool,
dependencies: Vec<PackageDependency>, pub dependencies: Vec<PackageDependency>,
edition: Edition, pub edition: Edition,
features: Vec<String>, pub features: Vec<String>,
out_dir: Option<PathBuf>, pub out_dir: Option<PathBuf>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -79,12 +96,12 @@ pub struct PackageDependency {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TargetData { pub struct TargetData {
pkg: Package, pub package: Package,
name: String, pub name: String,
root: PathBuf, pub root: PathBuf,
kind: TargetKind, pub kind: TargetKind,
is_proc_macro: bool, pub is_proc_macro: bool,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -115,52 +132,9 @@ impl TargetKind {
} }
} }
impl Package { impl PackageData {
pub fn name(self, ws: &CargoWorkspace) -> &str { pub fn root(&self) -> &Path {
ws.packages[self].name.as_str() self.manifest.parent().unwrap()
}
pub fn root(self, ws: &CargoWorkspace) -> &Path {
ws.packages[self].manifest.parent().unwrap()
}
pub fn edition(self, ws: &CargoWorkspace) -> Edition {
ws.packages[self].edition
}
pub fn features(self, ws: &CargoWorkspace) -> &[String] {
&ws.packages[self].features
}
pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + '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<Item = &'a PackageDependency> + 'a {
ws.packages[self].dependencies.iter()
}
pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> {
ws.packages[self].out_dir.as_ref().map(PathBuf::as_path)
}
}
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
}
pub fn is_proc_macro(self, ws: &CargoWorkspace) -> bool {
ws.targets[self].is_proc_macro
} }
} }
@ -219,7 +193,7 @@ impl CargoWorkspace {
for meta_tgt in meta_pkg.targets { for meta_tgt in meta_pkg.targets {
let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"]; let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
let tgt = targets.alloc(TargetData { let tgt = targets.alloc(TargetData {
pkg, package: pkg,
name: meta_tgt.name, name: meta_tgt.name,
root: meta_tgt.src_path.clone(), root: meta_tgt.src_path.clone(),
kind: TargetKind::new(meta_tgt.kind.as_slice()), kind: TargetKind::new(meta_tgt.kind.as_slice()),
@ -265,7 +239,10 @@ impl CargoWorkspace {
} }
pub fn target_by_root(&self, root: &Path) -> Option<Target> { pub fn target_by_root(&self, root: &Path) -> Option<Target> {
self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() self.packages()
.filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root))
.next()
.copied()
} }
pub fn workspace_root(&self) -> &Path { pub fn workspace_root(&self) -> &Path {

View file

@ -138,8 +138,8 @@ impl ProjectWorkspace {
ProjectWorkspace::Cargo { cargo, sysroot } => { ProjectWorkspace::Cargo { cargo, sysroot } => {
let mut roots = Vec::with_capacity(cargo.packages().len() + sysroot.crates().len()); let mut roots = Vec::with_capacity(cargo.packages().len() + sysroot.crates().len());
for pkg in cargo.packages() { for pkg in cargo.packages() {
let root = pkg.root(&cargo).to_path_buf(); let root = cargo[pkg].root().to_path_buf();
let member = pkg.is_member(&cargo); let member = cargo[pkg].is_member;
roots.push(PackageRoot::new(root, member)); roots.push(PackageRoot::new(root, member));
} }
for krate in sysroot.crates() { for krate in sysroot.crates() {
@ -164,7 +164,7 @@ impl ProjectWorkspace {
ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => { ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => {
let mut out_dirs = Vec::with_capacity(cargo.packages().len()); let mut out_dirs = Vec::with_capacity(cargo.packages().len());
for pkg in cargo.packages() { for pkg in cargo.packages() {
if let Some(out_dir) = pkg.out_dir(&cargo) { if let Some(out_dir) = &cargo[pkg].out_dir {
out_dirs.push(out_dir.to_path_buf()); out_dirs.push(out_dir.to_path_buf());
} }
} }
@ -309,18 +309,18 @@ impl ProjectWorkspace {
// Next, create crates for each package, target pair // Next, create crates for each package, target pair
for pkg in cargo.packages() { for pkg in cargo.packages() {
let mut lib_tgt = None; let mut lib_tgt = None;
for tgt in pkg.targets(&cargo) { for &tgt in cargo[pkg].targets.iter() {
let root = tgt.root(&cargo); let root = cargo[tgt].root.as_path();
if let Some(file_id) = load(root) { if let Some(file_id) = load(root) {
let edition = pkg.edition(&cargo); let edition = cargo[pkg].edition;
let cfg_options = { let cfg_options = {
let mut opts = default_cfg_options.clone(); let mut opts = default_cfg_options.clone();
opts.insert_features(pkg.features(&cargo).iter().map(Into::into)); opts.insert_features(cargo[pkg].features.iter().map(Into::into));
opts opts
}; };
let mut env = Env::default(); let mut env = Env::default();
let mut extern_source = ExternSource::default(); let mut extern_source = ExternSource::default();
if let Some(out_dir) = pkg.out_dir(cargo) { if let Some(out_dir) = &cargo[pkg].out_dir {
// FIXME: We probably mangle non UTF-8 paths here, figure out a better solution // FIXME: We probably mangle non UTF-8 paths here, figure out a better solution
env.set("OUT_DIR", out_dir.to_string_lossy().to_string()); env.set("OUT_DIR", out_dir.to_string_lossy().to_string());
if let Some(&extern_source_id) = extern_source_roots.get(out_dir) { if let Some(&extern_source_id) = extern_source_roots.get(out_dir) {
@ -330,16 +330,16 @@ impl ProjectWorkspace {
let crate_id = crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
file_id, file_id,
edition, edition,
Some(CrateName::normalize_dashes(pkg.name(&cargo))), Some(CrateName::normalize_dashes(&cargo[pkg].name)),
cfg_options, cfg_options,
env, env,
extern_source, extern_source,
); );
if tgt.kind(&cargo) == TargetKind::Lib { if cargo[tgt].kind == TargetKind::Lib {
lib_tgt = Some(crate_id); lib_tgt = Some(crate_id);
pkg_to_lib_crate.insert(pkg, crate_id); pkg_to_lib_crate.insert(pkg, crate_id);
} }
if tgt.is_proc_macro(&cargo) { if cargo[tgt].is_proc_macro {
if let Some(proc_macro) = libproc_macro { if let Some(proc_macro) = libproc_macro {
if crate_graph if crate_graph
.add_dep( .add_dep(
@ -351,7 +351,7 @@ impl ProjectWorkspace {
{ {
log::error!( log::error!(
"cyclic dependency on proc_macro for {}", "cyclic dependency on proc_macro for {}",
pkg.name(&cargo) &cargo[pkg].name
) )
} }
} }
@ -371,7 +371,7 @@ impl ProjectWorkspace {
// For root projects with dashes in their name, // For root projects with dashes in their name,
// cargo metadata does not do any normalization, // cargo metadata does not do any normalization,
// so we do it ourselves currently // so we do it ourselves currently
CrateName::normalize_dashes(pkg.name(&cargo)), CrateName::normalize_dashes(&cargo[pkg].name),
to, to,
) )
.is_err() .is_err()
@ -379,7 +379,7 @@ impl ProjectWorkspace {
{ {
log::error!( log::error!(
"cyclic dependency between targets of {}", "cyclic dependency between targets of {}",
pkg.name(&cargo) &cargo[pkg].name
) )
} }
} }
@ -391,7 +391,7 @@ impl ProjectWorkspace {
.add_dep(from, CrateName::new("core").unwrap(), core) .add_dep(from, CrateName::new("core").unwrap(), core)
.is_err() .is_err()
{ {
log::error!("cyclic dependency on core for {}", pkg.name(&cargo)) log::error!("cyclic dependency on core for {}", &cargo[pkg].name)
} }
} }
if let Some(alloc) = liballoc { if let Some(alloc) = liballoc {
@ -399,7 +399,7 @@ impl ProjectWorkspace {
.add_dep(from, CrateName::new("alloc").unwrap(), alloc) .add_dep(from, CrateName::new("alloc").unwrap(), alloc)
.is_err() .is_err()
{ {
log::error!("cyclic dependency on alloc for {}", pkg.name(&cargo)) log::error!("cyclic dependency on alloc for {}", &cargo[pkg].name)
} }
} }
if let Some(std) = libstd { if let Some(std) = libstd {
@ -407,7 +407,7 @@ impl ProjectWorkspace {
.add_dep(from, CrateName::new("std").unwrap(), std) .add_dep(from, CrateName::new("std").unwrap(), std)
.is_err() .is_err()
{ {
log::error!("cyclic dependency on std for {}", pkg.name(&cargo)) log::error!("cyclic dependency on std for {}", &cargo[pkg].name)
} }
} }
} }
@ -416,7 +416,7 @@ impl ProjectWorkspace {
// Now add a dep edge from all targets of upstream to the lib // Now add a dep edge from all targets of upstream to the lib
// target of downstream. // target of downstream.
for pkg in cargo.packages() { for pkg in cargo.packages() {
for dep in pkg.dependencies(&cargo) { for dep in cargo[pkg].dependencies.iter() {
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
for &from in pkg_crates.get(&pkg).into_iter().flatten() { for &from in pkg_crates.get(&pkg).into_iter().flatten() {
if crate_graph if crate_graph
@ -425,8 +425,8 @@ impl ProjectWorkspace {
{ {
log::error!( log::error!(
"cyclic dependency {} -> {}", "cyclic dependency {} -> {}",
pkg.name(&cargo), &cargo[pkg].name,
dep.pkg.name(&cargo) &cargo[dep.pkg].name
) )
} }
} }

View file

@ -77,9 +77,9 @@ impl CargoTargetSpec {
ProjectWorkspace::Cargo { cargo, .. } => { ProjectWorkspace::Cargo { cargo, .. } => {
let tgt = cargo.target_by_root(&path)?; let tgt = cargo.target_by_root(&path)?;
Some(CargoTargetSpec { Some(CargoTargetSpec {
package: tgt.package(&cargo).name(&cargo).to_string(), package: cargo[cargo[tgt].package].name.clone(),
target: tgt.name(&cargo).to_string(), target: cargo[tgt].name.clone(),
target_kind: tgt.kind(&cargo), target_kind: cargo[tgt].kind,
}) })
} }
ProjectWorkspace::Json { .. } => None, ProjectWorkspace::Json { .. } => None,