use std::collections::HashMap;
use anyhow::Result;
use futures::TryFutureExt;
use itertools::Itertools;
use crate::compiler::{CompilationUnit, CompilationUnitComponent, Profile};
use crate::core::package::{Package, PackageId};
use crate::core::registry::cache::RegistryCache;
use crate::core::registry::source_map::SourceMap;
use crate::core::registry::Registry;
use crate::core::resolver::Resolve;
use crate::core::workspace::Workspace;
use crate::core::Target;
use crate::resolver;
pub struct WorkspaceResolve {
pub resolve: Resolve,
pub packages: HashMap<PackageId, Package>,
}
impl WorkspaceResolve {
pub fn package_components_of(
&self,
root_package: PackageId,
) -> impl Iterator<Item = Package> + '_ {
assert!(self.packages.contains_key(&root_package));
self.resolve
.package_components_of(root_package)
.map(|id| self.packages[&id].clone())
}
}
#[tracing::instrument(
level = "debug",
skip_all,
fields(root = ws.root().to_string())
)]
pub fn resolve_workspace(ws: &Workspace<'_>) -> Result<WorkspaceResolve> {
ws.config().tokio_handle().block_on(
async {
let source_map = SourceMap::preloaded(ws.members(), ws.config());
let mut registry_cache = RegistryCache::new(source_map);
let members_summaries = ws
.members()
.map(|pkg| pkg.manifest.summary.clone())
.collect::<Vec<_>>();
let resolve = resolver::resolve(&members_summaries, &mut registry_cache).await?;
let packages =
collect_packages_from_resolve_graph(&resolve, &mut registry_cache).await?;
Ok(WorkspaceResolve { resolve, packages })
}
.into_future(),
)
}
#[tracing::instrument(skip_all, level = "debug")]
pub fn generate_compilation_units(
resolve: &WorkspaceResolve,
ws: &Workspace<'_>,
) -> Result<Vec<CompilationUnit>> {
let mut units = Vec::with_capacity(ws.members().size_hint().0);
for member in ws.members() {
let mut packages = resolve
.package_components_of(member.id)
.filter(|pkg| {
let is_self_or_lib = member.id == pkg.id || pkg.is_lib();
if !is_self_or_lib {
ws.config().ui().warn(format!(
"{} ignoring invalid dependency `{}` which is missing a lib target",
member.id, pkg.id.name
));
}
is_self_or_lib
})
.collect::<Vec<_>>();
packages.sort_by_key(|package| {
if package.id == member.id {
0
} else if package.id.is_core() {
1
} else {
2
}
});
for member_target in &member.manifest.targets {
let components = packages
.iter()
.cloned()
.map(|package| {
let target = if package.id == member.id {
member_target
} else {
package.fetch_target(Target::LIB).unwrap()
};
let target = target.clone();
CompilationUnitComponent { package, target }
})
.collect();
let unit = CompilationUnit {
main_package_id: member.id,
components,
profile: Profile {
name: "release".into(),
},
compiler_config: member.manifest.compiler_config.clone(),
};
units.push(unit);
}
}
assert!(
units.iter().map(CompilationUnit::id).all_unique(),
"All generated compilation units must have unique IDs."
);
Ok(units)
}
#[tracing::instrument(level = "trace", skip_all)]
async fn collect_packages_from_resolve_graph(
resolve: &Resolve,
registry: &mut RegistryCache<'_>,
) -> Result<HashMap<PackageId, Package>> {
let mut packages = HashMap::with_capacity(resolve.package_ids().size_hint().0);
for package_id in resolve.package_ids() {
let package = registry.download(package_id).await?;
packages.insert(package_id, package);
}
Ok(packages)
}