use cargo_metadata::{
Metadata, Package,
camino::{Utf8Path, Utf8PathBuf},
};
use eyre::eyre;
use super::{DistPackageConfig, DistPackageConfigBuilder};
use crate::Result;
#[derive(Debug)]
pub struct DistConfigBuilder<'a> {
name: String,
metadata: &'a Metadata,
dist_target_directory: Utf8PathBuf,
dist_base_working_directory: Utf8PathBuf,
packages: Vec<DistPackageConfig<'a>>,
#[cfg(feature = "subcommand-dist-build-bin")]
cargo_build_options: Vec<String>,
}
impl<'a> DistConfigBuilder<'a> {
pub fn new(name: impl Into<String>, workspace: &'a Metadata) -> Self {
let name = name.into();
let dist_target_directory = workspace.target_directory.join("dist");
let dist_base_working_directory = workspace.target_directory.join("xtask/dist").join(&name);
Self {
name,
metadata: workspace,
dist_target_directory,
dist_base_working_directory,
packages: vec![],
#[cfg(feature = "subcommand-dist-build-bin")]
cargo_build_options: vec![],
}
}
pub fn from_default_packages(
name: impl Into<String>,
workspace: &'a Metadata,
) -> (Self, Vec<DistPackageConfigBuilder<'a>>) {
Self::from_packages(name, workspace, &workspace.workspace_default_packages())
}
pub fn from_root_package(
workspace: &'a Metadata,
) -> Result<(Self, DistPackageConfigBuilder<'a>)> {
let package = workspace
.root_package()
.ok_or_else(|| eyre!("no root package found"))?;
Ok(Self::from_package(workspace, package))
}
pub fn from_package_name(
workspace: &'a Metadata,
name: &str,
) -> Result<(Self, DistPackageConfigBuilder<'a>)> {
let workspace_packages = workspace.workspace_packages();
let package = workspace_packages
.iter()
.find(|package| package.name == name)
.ok_or_else(|| eyre!("no package found"))?;
Ok(Self::from_package(workspace, package))
}
fn from_package(
workspace: &'a Metadata,
package: &'a Package,
) -> (Self, DistPackageConfigBuilder<'a>) {
let name = format!("{}-v{}", package.name, package.version);
let dist = Self::new(name, workspace);
let package_builder = DistPackageConfigBuilder::new(package);
(dist, package_builder)
}
fn from_packages(
name: impl Into<String>,
workspace: &'a Metadata,
packages: &[&'a Package],
) -> (Self, Vec<DistPackageConfigBuilder<'a>>) {
let name = name.into();
let dist = Self::new(name, workspace);
let package_builders = packages
.iter()
.copied()
.map(DistPackageConfigBuilder::new)
.collect();
(dist, package_builders)
}
pub fn package_by_name(&self, name: &str) -> Result<DistPackageConfigBuilder<'a>> {
let package = self
.metadata
.workspace_packages()
.into_iter()
.find(|package| package.name == name)
.ok_or_else(|| eyre!("no package found"))?;
let package_builder = DistPackageConfigBuilder::new(package);
Ok(package_builder)
}
pub fn package(mut self, package: DistPackageConfig<'a>) -> Self {
self.packages.push(package);
self
}
pub fn packages(mut self, packages: impl IntoIterator<Item = DistPackageConfig<'a>>) -> Self {
self.packages.extend(packages);
self
}
#[cfg(feature = "subcommand-dist-build-bin")]
#[cfg_attr(docsrs, doc(cfg(feature = "subcommand-dist-build-bin")))]
pub fn cargo_build_options(
mut self,
options: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.cargo_build_options
.extend(options.into_iter().map(Into::into));
self
}
pub fn build(self) -> Result<DistConfig<'a>> {
Ok(DistConfig {
name: self.name,
metadata: self.metadata,
dist_target_directory: self.dist_target_directory,
dist_base_working_directory: self.dist_base_working_directory,
packages: self.packages,
#[cfg(feature = "subcommand-dist-build-bin")]
cargo_build_options: self.cargo_build_options,
})
}
}
#[derive(Debug)]
pub struct DistConfig<'a> {
name: String,
metadata: &'a Metadata,
dist_target_directory: Utf8PathBuf,
dist_base_working_directory: Utf8PathBuf,
packages: Vec<DistPackageConfig<'a>>,
#[cfg(feature = "subcommand-dist-build-bin")]
cargo_build_options: Vec<String>,
}
impl<'a> DistConfig<'a> {
pub fn name(&self) -> &str {
&self.name
}
pub fn metadata(&self) -> &'a Metadata {
self.metadata
}
pub fn dist_target_directory(&self) -> &Utf8Path {
&self.dist_target_directory
}
pub fn dist_base_working_directory(&self) -> &Utf8Path {
&self.dist_base_working_directory
}
pub fn dist_working_directory(&self, target_triple: Option<&str>) -> Utf8PathBuf {
let target_triple = target_triple.unwrap_or("noarch");
self.dist_base_working_directory.join(target_triple)
}
pub fn packages(&'_ self) -> &'_ [DistPackageConfig<'_>] {
&self.packages
}
#[cfg(feature = "subcommand-dist-build-bin")]
#[cfg_attr(docsrs, doc(cfg(feature = "subcommand-dist-build-bin")))]
pub fn cargo_build_options(&self) -> &[String] {
&self.cargo_build_options
}
}