libcnb_package/
cargo.rs

1pub(crate) fn determine_buildpack_cargo_target_name(
2    cargo_metadata: &cargo_metadata::Metadata,
3) -> Result<String, DetermineBuildpackCargoTargetNameError> {
4    let root_package = cargo_metadata
5        .root_package()
6        .ok_or(DetermineBuildpackCargoTargetNameError::NoRootPackage)?;
7
8    let mut binary_target_names: Vec<String> =
9        cargo_binary_target_names_from_root_package(root_package);
10
11    match binary_target_names.len() {
12        0 | 1 => binary_target_names
13            .pop()
14            .ok_or(DetermineBuildpackCargoTargetNameError::NoBinTargets),
15        _ => binary_target_names
16            .contains(&root_package.name)
17            .then_some(root_package.name.to_string())
18            .ok_or(DetermineBuildpackCargoTargetNameError::AmbiguousBinTargets),
19    }
20}
21
22#[derive(thiserror::Error, Debug)]
23pub enum DetermineBuildpackCargoTargetNameError {
24    #[error("Cargo metadata is missing the required root package")]
25    NoRootPackage,
26    #[error("No binary targets could be found in Cargo metadata")]
27    NoBinTargets,
28    #[error("Ambiguous binary targets found in Cargo metadata")]
29    AmbiguousBinTargets,
30}
31
32/// Determines the names of all binary targets from the given Cargo metadata.
33pub(crate) fn cargo_binary_target_names(cargo_metadata: &cargo_metadata::Metadata) -> Vec<String> {
34    cargo_metadata
35        .root_package()
36        .map(cargo_binary_target_names_from_root_package)
37        .unwrap_or_default()
38}
39
40fn cargo_binary_target_names_from_root_package(
41    root_package: &cargo_metadata::Package,
42) -> Vec<String> {
43    root_package
44        .targets
45        .iter()
46        .filter_map(|target| target.is_bin().then_some(target.name.clone()))
47        .collect()
48}