| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| crate::gn::add_version_suffix, |
| crate::types::*, |
| camino::{Utf8Path, Utf8PathBuf}, |
| cargo_metadata::{Package, PackageId, Version}, |
| std::borrow::Cow, |
| std::cmp::Ordering, |
| std::collections::{hash_map::DefaultHasher, HashMap}, |
| std::hash::{Hash, Hasher}, |
| std::path::Path, |
| }; |
| |
| #[derive(Clone)] |
| pub struct CustomBuildTarget<'a> { |
| pub path: &'a Utf8Path, |
| pub dependencies: Vec<&'a Package>, |
| } |
| |
| pub struct GnTarget<'a> { |
| /// Package ID from the Cargo metadata |
| cargo_pkg_id: &'a PackageId, |
| /// Version of the Package from Cargo |
| version: &'a Version, |
| /// Name of the target given in Cargo.toml |
| pub target_name: &'a str, |
| /// Name of the package given in Cargo.toml |
| pub pkg_name: &'a str, |
| /// Path to the root of the crate |
| pub crate_root: &'a Utf8Path, |
| /// Rust Edition of the target |
| /// rustc: --edition |
| pub edition: &'a str, |
| /// Type of crate |
| /// rustc: --crate-type |
| pub target_type: GnRustType, |
| /// Rust features enabled on this target |
| /// rustc: --cfg=feature=<string> |
| pub features: &'a [String], |
| /// Target depends on Cargo running a custom build-script |
| pub build_script: Option<CustomBuildTarget<'a>>, |
| /// Target depends on Cargo running a custom build-script |
| pub dependencies: HashMap<Option<Platform>, Vec<(&'a Package, String)>>, |
| } |
| |
| impl std::fmt::Debug for GnTarget<'_> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| let display_name = if self.target_name != self.pkg_name { |
| Cow::Owned(format!("{}.{}", self.pkg_name, self.target_name)) |
| } else { |
| Cow::Borrowed(self.pkg_name) |
| }; |
| if self.build_script.is_some() { |
| write!(f, "{:?} with custom-build: {}", self.target_type, display_name) |
| } else { |
| write!(f, "{:?}: {}", self.target_type, display_name) |
| } |
| } |
| } |
| |
| impl PartialEq for GnTarget<'_> { |
| fn eq(&self, other: &Self) -> bool { |
| self.cargo_pkg_id == other.cargo_pkg_id && self.target_name == other.target_name |
| } |
| } |
| impl Eq for GnTarget<'_> {} |
| |
| impl PartialOrd for GnTarget<'_> { |
| fn partial_cmp(&self, other: &GnTarget<'_>) -> Option<Ordering> { |
| Some(self.cmp(other)) |
| } |
| } |
| |
| impl Ord for GnTarget<'_> { |
| fn cmp(&self, other: &GnTarget<'_>) -> Ordering { |
| self.cargo_pkg_id.cmp(&other.cargo_pkg_id).then(self.target_name.cmp(&other.target_name)) |
| } |
| } |
| |
| impl Hash for GnTarget<'_> { |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| self.cargo_pkg_id.hash(state); |
| self.target_name.hash(state); |
| } |
| } |
| |
| impl<'a> GnTarget<'a> { |
| pub fn new( |
| cargo_pkg_id: &'a PackageId, |
| target_name: &'a str, |
| pkg_name: &'a str, |
| edition: &'a str, |
| crate_root: &'a Utf8Path, |
| version: &'a Version, |
| target_type: GnRustType, |
| features: &'a [Feature], |
| build_script: Option<CustomBuildTarget<'a>>, |
| dependencies: HashMap<Option<Platform>, Vec<(&'a Package, String)>>, |
| ) -> Self { |
| GnTarget { |
| cargo_pkg_id, |
| target_name, |
| pkg_name, |
| edition, |
| crate_root, |
| version, |
| target_type, |
| features, |
| build_script, |
| dependencies, |
| } |
| } |
| |
| pub fn uses_build_script(&self) -> bool { |
| self.build_script.is_some() |
| } |
| |
| /// Name of the target given in Cargo.toml |
| pub fn name(&self) -> String { |
| self.target_name.to_owned() |
| } |
| |
| /// Version of the Package from Cargo |
| pub fn version(&self) -> String { |
| self.version.to_string() |
| } |
| |
| pub fn metadata_hash(&self) -> String { |
| let mut hasher = DefaultHasher::new(); |
| self.gn_target_name().hash(&mut hasher); |
| format!("{:x}", hasher.finish()) |
| } |
| |
| /// with version |
| pub fn gn_target_name(&self) -> String { |
| let prefix = match self.target_type { |
| GnRustType::Library | GnRustType::ProcMacro => Cow::Borrowed(self.pkg_name), |
| GnRustType::Binary => Cow::Owned(format!("{}-{}", self.pkg_name, self.target_name)), |
| ty => panic!("Don't know how to represent this type \"{:?}\" in GN", ty), |
| }; |
| add_version_suffix(&prefix, &self.version) |
| } |
| |
| pub fn package_root(&self, project_root: &Path) -> Utf8PathBuf { |
| let mut package_root = self.crate_root; |
| |
| while !package_root.join("Cargo.toml").exists() { |
| package_root = package_root |
| .parent() |
| .expect("searching up from the crate root we must find a cargo.toml"); |
| } |
| |
| let package_root = package_root.strip_prefix(project_root).unwrap_or_else(|e| { |
| panic!("{}: {} is not under FUCHSIA_DIR({})", e, package_root, project_root.display()) |
| }); |
| assert_ne!( |
| package_root.as_os_str(), |
| "third_party/rust_crates", |
| "must find a cargo.toml before the root one" |
| ); |
| |
| package_root.to_owned() |
| } |
| |
| pub fn gn_target_type(&self) -> String { |
| match self.target_type { |
| GnRustType::Library => String::from("rust_library"), |
| GnRustType::Binary => String::from("executable"), |
| GnRustType::ProcMacro => String::from("rust_proc_macro"), |
| ty => panic!("Don't know how to represent this type \"{:?}\" in GN", ty), |
| } |
| } |
| } |