use std::fmt;
use anyhow::Result;
use camino::Utf8Path;
use scarb_metadata::packages_filter::PackagesSource;
use crate::compiler::Profile;
use crate::core::config::Config;
use crate::core::package::Package;
use crate::flock::RootFilesystem;
use crate::MANIFEST_FILE_NAME;
pub struct Workspace<'c> {
config: &'c Config,
package: Package,
}
impl<'c> Workspace<'c> {
pub(crate) fn from_single_package(package: Package, config: &'c Config) -> Result<Self> {
Ok(Self { config, package })
}
pub fn config(&self) -> &'c Config {
self.config
}
pub fn root(&self) -> &Utf8Path {
self.package.root()
}
pub fn manifest_path(&self) -> &Utf8Path {
self.package.manifest_path()
}
pub fn target_dir(&self) -> &RootFilesystem {
self.config.target_dir()
}
pub fn current_package(&self) -> Result<&Package> {
Ok(&self.package)
}
pub fn members(&self) -> impl Iterator<Item = Package> {
[self.package.clone()].into_iter()
}
pub fn current_profile(&self) -> Result<Profile> {
let profile = self.config.profile();
if profile.is_custom() && !self.current_package()?.has_profile(&profile) {
anyhow::bail!(
"package `{}` has no profile `{}`",
self.current_package()?,
profile
);
}
Ok(profile)
}
pub fn profile_names(&self) -> Result<Vec<String>> {
let mut names = self
.current_package()?
.manifest
.profiles
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>();
names.push(Profile::DEV.to_string());
names.push(Profile::RELEASE.to_string());
names.sort();
Ok(names)
}
}
impl<'c> fmt::Display for Workspace<'c> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let manifest_path = self.manifest_path();
let path = if manifest_path.file_name() == Some(MANIFEST_FILE_NAME) {
self.root()
} else {
manifest_path
};
write!(f, "{path}")
}
}
impl<'c> fmt::Debug for Workspace<'c> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Workspace")
.field("package", &self.package)
.finish_non_exhaustive()
}
}
pub trait Utf8PathWorkspaceExt {
fn workspace_relative(&self, ws: &Workspace<'_>) -> &Utf8Path;
}
impl Utf8PathWorkspaceExt for Utf8Path {
fn workspace_relative(&self, ws: &Workspace<'_>) -> &Utf8Path {
self.strip_prefix(ws.root()).unwrap_or(self)
}
}
impl<'c> PackagesSource for Workspace<'c> {
type Package = Package;
fn package_name_of(package: &Self::Package) -> &str {
package.id.name.as_str()
}
fn members(&self) -> Vec<Self::Package> {
Workspace::members(self).collect()
}
}