use ra_ap_project_model::{CargoWorkspace, Package, Target, TargetKind};
use crate::options::project::Options;
pub fn select_package(workspace: &CargoWorkspace, options: &Options) -> anyhow::Result<Package> {
let packages: Vec<_> = workspace
.packages()
.filter(|idx| workspace[*idx].is_member)
.collect();
let package_count = packages.len();
if package_count < 1 {
anyhow::bail!("No packages found");
}
let package_list_items: Vec<_> = packages
.iter()
.map(|package_idx| {
let package = &workspace[*package_idx];
format!("- {}", package.name)
})
.collect();
let package_list = package_list_items.join("\n");
if let Some(package_name) = &options.package {
let package_idx = packages.into_iter().find(|package_idx| {
let package = &workspace[*package_idx];
package.name == *package_name
});
return package_idx.ok_or_else(|| {
anyhow::anyhow!(
indoc::indoc! {
"No package found with name {:?}.
Packages present in workspace:
{}
"
},
package_name,
package_list,
)
});
}
if package_count == 1 {
return Ok(packages[0]);
}
Err(anyhow::anyhow!(
indoc::indoc! {
"Multiple packages present in workspace,
please explicitly select one via --package flag.
Packages present in workspace:
{}
"
},
package_list
))
}
pub fn select_target(
workspace: &CargoWorkspace,
package_idx: Package,
options: &Options,
) -> anyhow::Result<Target> {
let package = &workspace[package_idx];
let targets: Vec<_> = package
.targets
.iter()
.cloned()
.filter(|target_idx| {
let target = &workspace[*target_idx];
match target.kind {
TargetKind::Bin => true,
TargetKind::Lib => true,
TargetKind::Example => false,
TargetKind::Test => false,
TargetKind::Bench => false,
TargetKind::Other => false,
TargetKind::BuildScript => false,
}
})
.collect();
let target_count = targets.len();
if target_count < 1 {
anyhow::bail!("No targets found");
}
let target_list_items: Vec<_> = targets
.iter()
.map(|target_idx| {
let target = &workspace[*target_idx];
match target.kind {
TargetKind::Bin => format!("- {} (--bin {})", target.name, target.name),
TargetKind::Lib => format!("- {} (--lib)", target.name),
TargetKind::Example => unreachable!(),
TargetKind::Test => unreachable!(),
TargetKind::Bench => unreachable!(),
TargetKind::Other => unreachable!(),
TargetKind::BuildScript => unreachable!(),
}
})
.collect();
let target_list = target_list_items.join("\n");
if options.lib {
let target = targets.into_iter().find(|target_idx| {
let target = &workspace[*target_idx];
target.kind == TargetKind::Lib
});
return target.ok_or_else(|| {
anyhow::anyhow!(
indoc::indoc! {
"No library target found.
Targets present in package:
{}
"
},
target_list,
)
});
}
if let Some(bin_name) = &options.bin {
let target = targets.into_iter().find(|target_idx| {
let target = &workspace[*target_idx];
(target.kind == TargetKind::Bin) && (target.name == bin_name[..])
});
return target.ok_or_else(|| {
anyhow::anyhow!(
indoc::indoc! {
"No binary target found with name {:?}.
Targets present in package:
{}
"
},
bin_name,
target_list,
)
});
}
if target_count == 1 {
return Ok(targets[0]);
}
Err(anyhow::anyhow!(
indoc::indoc! {
"Multiple targets present in package,
please explicitly select one via --lib or --bin flag.
Targets present in package:
{}
"
},
target_list
))
}