use std::collections::HashSet;
use std::path::PathBuf;
use serde_json::Value;
use serde_json::json;
use super::cargo_detector::BevyTarget;
use super::cargo_detector::BrpLevel;
use super::cargo_detector::CargoDetector;
use super::constants::BRP_LEVEL_FIELD;
use super::constants::BUILD_BUILT_FIELD;
use super::constants::BUILDS_FIELD;
use super::constants::KIND_FIELD;
use super::constants::NAME_FIELD;
use super::constants::PACKAGE_NAME_FIELD;
use super::constants::PATH_FIELD;
use super::constants::RELATIVE_PATH_FIELD;
use super::constants::WORKSPACE_ROOT_FIELD;
use super::scanning;
use crate::app_tools::constants::MANIFEST_PATH_FIELD;
use crate::app_tools::constants::PROFILE_DEBUG;
use crate::app_tools::constants::PROFILE_RELEASE;
pub(super) struct AllBevyTargetsStrategy;
pub(super) struct EnrichedTarget {
pub(super) target: BevyTarget,
pub(super) brp_level: BrpLevel,
}
impl AllBevyTargetsStrategy {
pub(super) fn collect_items(detector: &CargoDetector) -> Vec<EnrichedTarget> {
let all_targets = detector.find_bevy_targets();
let brp_targets = detector.find_brp_targets();
let brp_keys: HashSet<String> = brp_targets
.iter()
.map(|t| format!("{}::{}", t.manifest.display(), t.name))
.collect();
all_targets
.into_iter()
.map(|target| {
let brp_level = if target.is_app() {
let key = format!("{}::{}", target.manifest.display(), target.name);
if brp_keys.contains(&key) {
CargoDetector::file_brp_level(&target.source)
} else {
BrpLevel::None
}
} else {
CargoDetector::file_brp_level(&target.source)
};
EnrichedTarget { target, brp_level }
})
.collect()
}
pub(super) fn create_unique_key(item: &EnrichedTarget) -> String {
format!(
"{}::{}::{}",
item.target.manifest.display(),
item.target.name,
item.target.target_type.as_ref()
)
}
pub(super) fn get_path_for_relative(item: &EnrichedTarget) -> PathBuf {
item.target
.manifest
.parent()
.unwrap_or(&item.target.manifest)
.to_path_buf()
}
pub(super) fn serialize_item(item: &EnrichedTarget, relative_path: String) -> Value {
json!({
NAME_FIELD: item.target.name,
KIND_FIELD: item.target.target_type.as_ref(),
PACKAGE_NAME_FIELD: item.target.package_name,
BRP_LEVEL_FIELD: item.brp_level.as_str(),
WORKSPACE_ROOT_FIELD: item.target.workspace_root.display().to_string(),
MANIFEST_PATH_FIELD: item.target.manifest.display().to_string(),
RELATIVE_PATH_FIELD: relative_path,
BUILDS_FIELD: create_builds_json(&item.target)
})
}
}
pub fn collect_all_bevy_targets(search_paths: &[PathBuf]) -> Vec<Value> {
let mut all_items = Vec::new();
let mut seen_items = HashSet::new();
for path in scanning::iter_cargo_project_paths(search_paths) {
if let Ok(detector) = CargoDetector::try_from(path.as_path()) {
let items = AllBevyTargetsStrategy::collect_items(&detector);
for item in items {
let key = AllBevyTargetsStrategy::create_unique_key(&item);
if seen_items.insert(key) {
let item_path = AllBevyTargetsStrategy::get_path_for_relative(&item);
let relative_path = scanning::compute_relative_path(&item_path, search_paths);
let serialized_item = AllBevyTargetsStrategy::serialize_item(
&item,
relative_path.display().to_string(),
);
all_items.push(serialized_item);
}
}
}
}
all_items
}
fn create_builds_json(item: &BevyTarget) -> Value {
let profiles = vec![PROFILE_DEBUG, PROFILE_RELEASE];
let mut builds = json!({});
for profile in &profiles {
let binary_path = item.get_binary_path(profile);
builds[profile] = json!({
PATH_FIELD: binary_path.display().to_string(),
BUILD_BUILT_FIELD: binary_path.exists()
});
}
builds
}