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
32pub(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}