use std::collections::BTreeMap;
use std::path::PathBuf;
use cabin_core::{
CompilerWrapperManifestSettings, Condition, DependencyKind, Package, PatchManifestSettings,
ProfileDefinition, ProfileName, ToolchainSettings,
};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RootSettings {
pub profiles: BTreeMap<ProfileName, ProfileDefinition>,
pub toolchain: ToolchainSettings,
pub compiler_wrapper: CompilerWrapperManifestSettings,
pub patches: PatchManifestSettings,
}
impl From<cabin_manifest::RootSettings> for RootSettings {
fn from(value: cabin_manifest::RootSettings) -> Self {
Self {
profiles: value.profiles,
toolchain: value.toolchain,
compiler_wrapper: value.compiler_wrapper,
patches: value.patches,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PackageGraph {
pub root_manifest_path: PathBuf,
pub root_dir: PathBuf,
pub is_workspace_root: bool,
pub root_package: Option<usize>,
pub root_settings: RootSettings,
pub primary_packages: Vec<usize>,
pub default_members: Vec<usize>,
pub excluded_members: Vec<PathBuf>,
pub packages: Vec<WorkspacePackage>,
}
impl PackageGraph {
pub fn package_by_name(&self, name: &str) -> Option<&WorkspacePackage> {
self.packages
.iter()
.find(|p| p.package.name.as_str() == name)
}
pub fn index_of(&self, name: &str) -> Option<usize> {
self.packages
.iter()
.position(|p| p.package.name.as_str() == name)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkspacePackage {
pub package: Package,
pub manifest_path: PathBuf,
pub manifest_dir: PathBuf,
pub deps: Vec<DependencyEdge>,
pub kind: PackageKind,
}
impl WorkspacePackage {
pub fn deps_of_kind(&self, kind: DependencyKind) -> impl Iterator<Item = usize> + '_ {
self.deps
.iter()
.filter(move |edge| edge.kind == kind)
.map(|edge| edge.index)
}
pub fn all_dep_indices(&self) -> impl Iterator<Item = usize> + '_ {
self.deps.iter().map(|edge| edge.index)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DependencyEdge {
pub index: usize,
pub kind: DependencyKind,
pub condition: Option<Condition>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PackageKind {
Local,
Registry,
}
pub fn synthetic_root_identity(graph: &PackageGraph) -> (cabin_core::PackageName, semver::Version) {
let dirname = graph
.root_dir
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("workspace");
let mut sanitized = String::with_capacity(dirname.len() + 12);
sanitized.push_str("__workspace_");
for c in dirname.chars() {
if c.is_ascii_alphanumeric() || matches!(c, '_' | '-') {
sanitized.push(c);
} else {
sanitized.push('_');
}
}
let name =
cabin_core::PackageName::new(sanitized).expect("synthesized name is non-empty and ASCII");
let version = semver::Version::new(0, 0, 0);
(name, version)
}