| // 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::cfg::{cfg_to_gn_conditional, target_to_gn_conditional}; |
| use crate::target::GnTarget; |
| use crate::types::*; |
| use crate::{ |
| BinaryRenderOptions, CombinedTargetCfg, GlobalTargetCfgs, GroupVisibility, RuleRenaming, |
| }; |
| use anyhow::{Context, Result}; |
| use cargo_metadata::Package; |
| use std::borrow::Cow; |
| use std::collections::BTreeMap; |
| use std::fmt::Display; |
| use std::io::{self, Write}; |
| use std::path::Path; |
| use walkdir::WalkDir; |
| |
| /// Utility to add a version suffix to a GN target name. |
| pub fn add_version_suffix(prefix: &str, version: &impl ToString) -> String { |
| let mut accum = String::new(); |
| accum.push_str(&prefix); |
| accum.push_str("-v"); |
| accum.push_str(version.to_string().replace('.', "_").as_str()); |
| accum |
| } |
| |
| /// Write a header for the output GN file |
| pub fn write_header<W: io::Write>(output: &mut W, _cargo_file: &Path) -> Result<()> { |
| writeln!( |
| output, |
| include_str!("../templates_pw/gn_header.template"), |
| // TODO set this, but in a way that tests don't fail on Jan 1st |
| year = "2020", |
| ) |
| .map_err(Into::into) |
| } |
| |
| pub fn write_fuchsia_sdk_metadata_header<W: io::Write>(output: &mut W) -> Result<()> { |
| writeln!(output, include_str!("../templates_pw/gn_sdk_metadata_header.template"),) |
| .map_err(Into::into) |
| } |
| |
| /// Write an import stament for the output GN file |
| pub fn write_import<W: io::Write>(output: &mut W, file_name: &str) -> Result<()> { |
| writeln!(output, include_str!("../templates_pw/gn_import.template"), file_name = file_name) |
| .map_err(Into::into) |
| } |
| |
| /// Writes rules at the top of the GN file that don't have the version appended |
| /// |
| /// Args: |
| /// - `rule_renaming`: if set, the renaming rules will be used to generate |
| /// appropriate group and rule names. See [RuleRenaming] for details. |
| pub fn write_top_level_rule<W: io::Write>( |
| output: &mut W, |
| platform: Option<&str>, |
| pkg: &Package, |
| group_visibility: Option<&GroupVisibility>, |
| rule_renaming: Option<&RuleRenaming>, |
| testonly: bool, |
| has_tests: bool, |
| ) -> Result<()> { |
| let target_name = pkg.gn_name(); |
| if let Some(ref platform) = platform { |
| writeln!( |
| output, |
| "if ({conditional}) {{\n", |
| conditional = target_to_gn_conditional(platform)? |
| )?; |
| } |
| |
| let group_rule = rule_renaming.and_then(|t| t.group_name.as_deref()).unwrap_or("group"); |
| let optional_visibility = |
| group_visibility.map(|v| format!("visibility = {}", v.variable)).unwrap_or_default(); |
| writeln!( |
| output, |
| include_str!("../templates_pw/top_level_gn_rule.template"), |
| group_name = pkg.name, |
| dep_name = target_name, |
| group_rule_name = group_rule, |
| optional_visibility = optional_visibility, |
| optional_testonly = if testonly { "testonly = true" } else { "" }, |
| )?; |
| |
| if has_tests { |
| let name = pkg.name.clone() + "-test"; |
| writeln!( |
| output, |
| include_str!("../templates_pw/top_level_gn_rule.template"), |
| group_name = name, |
| group_rule_name = group_rule, |
| dep_name = target_name + "-test", |
| optional_visibility = optional_visibility, |
| optional_testonly = "testonly = true", |
| )?; |
| } |
| |
| if platform.is_some() { |
| writeln!(output, "}}\n")?; |
| } |
| Ok(()) |
| } |
| |
| /// Writes Fuchsia SDK metadata for a top-level rule. |
| pub fn write_fuchsia_sdk_metadata<W: io::Write>( |
| output: &mut W, |
| platform: Option<&str>, |
| pkg: &Package, |
| abs_dir: &Path, |
| rel_dir: &Path, |
| ) -> Result<()> { |
| // TODO: add features, and registry |
| std::fs::create_dir_all(abs_dir) |
| .with_context(|| format!("while making directories for {}", abs_dir.display()))?; |
| |
| let file_name = format!("{}.sdk.meta.json", pkg.name); |
| let abs_path = abs_dir.join(&file_name); |
| let rel_path = rel_dir.join(&file_name); |
| let mut metadata_output = std::fs::File::create(&abs_path) |
| .with_context(|| format!("while writing {}", abs_path.display()))?; |
| writeln!( |
| metadata_output, |
| r#"{{ |
| "type": "{sdk_atom_type}", |
| "name": "{group_name}", |
| "version": "{version}" |
| }}"#, |
| sdk_atom_type = if pkg.is_proc_macro() { "rust_3p_proc_macro" } else { "rust_3p_library" }, |
| group_name = pkg.name, |
| version = pkg.version, |
| )?; |
| |
| let platform_constraint = if let Some(p) = platform { |
| format!(" && {}", target_to_gn_conditional(p)?) |
| } else { |
| "".to_owned() |
| }; |
| |
| writeln!( |
| output, |
| r#" if (_generating_sdk{constraint}) {{ |
| sdk_atom("{group_name}_sdk") {{ |
| id = "sdk://${{_sdk_prefix}}third_party/rust_crates/{group_name}" |
| category = "internal" |
| meta = {{ |
| source = "{source}" |
| dest = "${{_sdk_prefix}}third_party/rust_crates/{group_name}/meta.json" |
| schema = "3p_rust_library" |
| }} |
| }} |
| }} |
| "#, |
| constraint = platform_constraint, |
| source = rel_path.display(), |
| group_name = pkg.name, |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Writes rules at the top of the GN file that don't have the version appended |
| pub fn write_binary_top_level_rule<'a, W: io::Write>( |
| output: &mut W, |
| platform: Option<String>, |
| target: &GnTarget<'a>, |
| options: &BinaryRenderOptions<'_>, |
| ) -> Result<()> { |
| if let Some(ref platform) = platform { |
| writeln!( |
| output, |
| "if ({conditional}) {{\n", |
| conditional = cfg_to_gn_conditional(platform)? |
| )?; |
| } |
| writeln!( |
| output, |
| include_str!("../templates_pw/top_level_binary_gn_rule.template"), |
| group_name = options.binary_name, |
| dep_name = target.gn_target_name(), |
| optional_testonly = "", |
| )?; |
| |
| if options.tests_enabled { |
| let name = options.binary_name.to_owned() + "-test"; |
| let dep_name = target.gn_target_name() + "-test"; |
| writeln!( |
| output, |
| include_str!("../templates_pw/top_level_binary_gn_rule.template"), |
| group_name = name, |
| dep_name = dep_name, |
| optional_testonly = "testonly = true", |
| )?; |
| } |
| |
| if platform.is_some() { |
| writeln!(output, "}}\n")?; |
| } |
| Ok(()) |
| } |
| |
| struct GnField { |
| ty: String, |
| exists: bool, |
| // Use BTreeMap so that iteration over platforms is stable. |
| add_fields: BTreeMap<Option<Platform>, Vec<String>>, |
| remove_fields: BTreeMap<Option<Platform>, Vec<String>>, |
| } |
| impl GnField { |
| /// If defining a new field in the template |
| pub fn new(ty: &str) -> GnField { |
| GnField { |
| ty: ty.to_string(), |
| exists: false, |
| add_fields: BTreeMap::new(), |
| remove_fields: BTreeMap::new(), |
| } |
| } |
| |
| /// If the field already exists in the template |
| pub fn exists(ty: &str) -> GnField { |
| GnField { exists: true, ..Self::new(ty) } |
| } |
| |
| pub fn add_platform_cfg<T: AsRef<str> + Display>(&mut self, platform: Option<String>, cfg: T) { |
| let field = self.add_fields.entry(platform).or_default(); |
| field.push(format!("\"{}\"", cfg)); |
| } |
| |
| pub fn remove_platform_cfg<T: AsRef<str> + Display>( |
| &mut self, |
| platform: Option<String>, |
| cfg: T, |
| ) { |
| let field = self.remove_fields.entry(platform).or_default(); |
| field.push(format!("\"{}\"", cfg)); |
| } |
| |
| pub fn add_cfg<T: AsRef<str> + Display>(&mut self, cfg: T) { |
| self.add_platform_cfg(None, cfg) |
| } |
| |
| pub fn remove_cfg<T: AsRef<str> + Display>(&mut self, cfg: T) { |
| self.remove_platform_cfg(None, cfg) |
| } |
| |
| pub fn render_gn(&self) -> String { |
| let mut output = if self.exists { |
| // We don't create an empty [] if the field already exists |
| match self.add_fields.get(&None) { |
| Some(add_fields) => format!("{} += [{}]\n", self.ty, add_fields.join(",")), |
| None => "".to_string(), |
| } |
| } else { |
| format!("{} = [{}]\n", self.ty, self.add_fields.get(&None).unwrap_or(&vec![]).join(",")) |
| }; |
| |
| // remove platfrom independent configs |
| if let Some(rm_fields) = self.remove_fields.get(&None) { |
| output.push_str(format!("{} -= [{}]\n", self.ty, rm_fields.join(",")).as_str()); |
| } |
| |
| // Add logic for specific platforms |
| for platform in self.add_fields.keys().filter(|k| k.is_some()) { |
| output.push_str( |
| format!( |
| "if ({}) {{\n", |
| cfg_to_gn_conditional(platform.as_ref().unwrap()).expect("valid cfg") |
| ) |
| .as_str(), |
| ); |
| output.push_str( |
| format!( |
| "{} += [{}]", |
| self.ty, |
| self.add_fields.get(platform).unwrap_or(&vec![]).join(",") |
| ) |
| .as_str(), |
| ); |
| output.push_str("}\n"); |
| } |
| |
| // Remove logic for specific platforms |
| for platform in self.remove_fields.keys().filter(|k| k.is_some()) { |
| output.push_str( |
| format!( |
| "if ({}) {{\n", |
| cfg_to_gn_conditional(platform.as_ref().unwrap()).expect("valid cfg") |
| ) |
| .as_str(), |
| ); |
| output.push_str( |
| format!( |
| "{} -= [{}]", |
| self.ty, |
| self.remove_fields.get(platform).unwrap_or(&vec![]).join(",") |
| ) |
| .as_str(), |
| ); |
| output.push_str("}\n"); |
| } |
| output |
| } |
| } |
| |
| /// Write a Target to the GN file. |
| /// |
| /// Includes information from the build script. |
| /// |
| /// Args: |
| /// - `renamed_rule`: if this is set, the rule that is written out is changed |
| /// to be the content of this arg. |
| pub fn write_rule<W: io::Write>( |
| output: &mut W, |
| target: &GnTarget<'_>, |
| project_root: &Path, |
| global_target_cfgs: Option<&GlobalTargetCfgs>, |
| custom_build: Option<&CombinedTargetCfg<'_>>, |
| output_name: Option<&str>, |
| is_testonly: bool, |
| is_test: bool, |
| renamed_rule: Option<&str>, |
| scan_for_licenses: bool, |
| ) -> Result<()> { |
| // Generate a section for dependencies that is paramaterized on toolchain |
| let mut dependencies = String::from("deps = []\n"); |
| let mut aliased_deps = vec![]; |
| |
| // Stable output of platforms |
| let mut platform_deps: Vec<( |
| &Option<String>, |
| &Vec<(&cargo_metadata::Package, std::string::String)>, |
| )> = target.dependencies.iter().collect(); |
| platform_deps.sort_by(|p, p2| p.0.cmp(p2.0)); |
| |
| for (platform, deps) in platform_deps { |
| // sort for stable output |
| let mut deps = deps.clone(); |
| deps.sort_by(|a, b| (a.0).id.cmp(&(b.0).id)); |
| |
| // TODO(bwb) feed GN toolchain mapping in as a configuration to make more generic |
| match platform.as_ref().map(String::as_str) { |
| None => { |
| for pkg in deps { |
| dependencies.push_str(" deps += ["); |
| dependencies.push_str(format!("\":{}\"", pkg.0.gn_name()).as_str()); |
| dependencies.push_str("]\n"); |
| if pkg.0.name.replace("-", "_") != pkg.1 { |
| aliased_deps.push(format!("{} = \":{}\" ", pkg.1, pkg.0.gn_name())); |
| } |
| } |
| } |
| Some(platform) => { |
| dependencies.push_str( |
| format!("if ({}) {{\n", target_to_gn_conditional(platform)?).as_str(), |
| ); |
| for pkg in deps { |
| dependencies.push_str(" deps += ["); |
| dependencies.push_str(format!("\":{}\"", pkg.0.gn_name()).as_str()); |
| dependencies.push_str("]\n"); |
| |
| if pkg.0.name.replace("-", "_") != pkg.1 { |
| aliased_deps.push(format!("{} = \":{}\" ", pkg.1, pkg.0.gn_name())); |
| } |
| } |
| dependencies.push_str("}\n"); |
| } |
| } |
| } |
| |
| // write the features into the configs |
| let mut rustflags = GnField::new("rustflags"); |
| let mut rustenv = GnField::new("rustenv"); |
| let mut configs = GnField::exists("configs"); |
| let mut require_licenses = false; |
| |
| if let Some(global_cfg) = global_target_cfgs { |
| for cfg in &global_cfg.remove_cfgs { |
| configs.remove_cfg(cfg); |
| } |
| for cfg in &global_cfg.add_cfgs { |
| configs.add_cfg(cfg); |
| } |
| if let Some(ref require) = global_cfg.require_licenses { |
| require_licenses = *require; |
| } |
| } |
| |
| // Associate unique metadata with this crate |
| rustflags.add_cfg("--cap-lints=allow"); |
| rustflags.add_cfg(format!("-Cmetadata={}", target.metadata_hash())); |
| rustflags.add_cfg(format!("-Cextra-filename=-{}", target.metadata_hash())); |
| if is_test { |
| rustflags.add_cfg("--test"); |
| } |
| |
| // Aggregate feature flags |
| for feature in target.features { |
| rustflags.add_cfg(format!("--cfg=feature=\\\"{}\\\"", feature)); |
| } |
| |
| // From the gn custom configs, add flags, env vars, and visibility |
| let mut visibility = vec![]; |
| |
| let mut uses_fuchsia_license = false; |
| |
| if let Some(custom_build) = custom_build { |
| for (platform, cfg) in custom_build { |
| if let Some(ref deps) = cfg.deps { |
| let build_deps = |dependencies: &mut String| { |
| for dep in deps { |
| dependencies.push_str(format!(" deps += [\"{}\"]", dep).as_str()); |
| } |
| }; |
| if let Some(platform) = platform { |
| dependencies.push_str( |
| format!("if ({}) {{\n", target_to_gn_conditional(platform)?).as_str(), |
| ); |
| build_deps(&mut dependencies); |
| dependencies.push_str("}\n"); |
| } else { |
| build_deps(&mut dependencies); |
| } |
| } |
| if let Some(ref flags) = cfg.rustflags { |
| for flag in flags { |
| rustflags.add_platform_cfg(platform.cloned(), flag.to_string()); |
| } |
| } |
| if let Some(ref env_vars) = cfg.env_vars { |
| for flag in env_vars { |
| rustenv.add_platform_cfg(platform.cloned(), flag.to_string()); |
| } |
| } |
| if let Some(ref crate_configs) = cfg.configs { |
| for config in crate_configs { |
| configs.add_platform_cfg(platform.cloned(), config); |
| } |
| } |
| if let Some(ref vis) = cfg.visibility { |
| visibility.extend(vis.iter().map(|v| format!(" visibility += [\"{}\"]", v))); |
| } |
| if let Some(ref uses) = cfg.uses_fuchsia_license { |
| uses_fuchsia_license = *uses; |
| } |
| } |
| } |
| |
| let edition = format!("edition = \"{}\"", target.edition); |
| |
| let visibility = if visibility.is_empty() { |
| String::from("visibility = [\":*\"]\n") |
| } else { |
| let mut v = String::from("visibility = []\n"); |
| v.extend(visibility); |
| v |
| }; |
| |
| // making the templates more readable. |
| let aliased_deps_str = if aliased_deps.is_empty() { |
| String::from("") |
| } else { |
| format!("aliased_deps = {{{}}}", aliased_deps.join("\n")) |
| }; |
| |
| // GN root relative path |
| let root_relative_path = format!( |
| "//{}", |
| target |
| .crate_root |
| .canonicalize_utf8() |
| .unwrap() |
| .strip_prefix(project_root) |
| .with_context(|| format!( |
| "{} is located outside of the project. Check your vendoring setup", |
| target.name() |
| ))? |
| .to_string() |
| ); |
| let output_name = if is_test { |
| output_name.map_or_else( |
| || { |
| Cow::Owned(format!( |
| "{}-{}-test", |
| target.name().replace('-', "_"), |
| target.metadata_hash() |
| )) |
| }, |
| |n| Cow::Owned(format!("{}-test", n)), |
| ) |
| } else { |
| output_name.map_or_else( |
| || { |
| Cow::Owned(format!( |
| "{}-{}", |
| target.name().replace('-', "_"), |
| target.metadata_hash() |
| )) |
| }, |
| Cow::Borrowed, |
| ) |
| }; |
| let mut target_name = target.gn_target_name(); |
| if is_test { |
| target_name.push_str("-test"); |
| } |
| |
| let optional_testonly = if is_testonly || is_test { "testonly = true" } else { "" }; |
| |
| let gn_rule = if let Some(renamed_rule) = renamed_rule { |
| renamed_rule.to_owned() |
| } else if is_test { |
| "executable".to_owned() |
| } else { |
| target.gn_target_type() |
| }; |
| |
| let mut license_files_found = false; |
| let mut gn_applicable_licenses : Option<GnField> = None; |
| let gn_crate_name = target.name().replace('-', "_"); |
| |
| if scan_for_licenses { |
| let mut applicable_licenses = GnField::new("applicable_licenses"); |
| |
| // Scan for LICENSE* files in the crate's root dir. |
| // Disabled in unit tests, where package_root always fails. |
| let mut license_files = vec![]; |
| |
| for entry in WalkDir::new(target.package_root()).follow_links(false).into_iter() { |
| let entry = entry.unwrap(); |
| let file_name_lower = entry.file_name().to_string_lossy().to_lowercase(); |
| if file_name_lower.starts_with("license") |
| || file_name_lower.starts_with("licence") |
| || file_name_lower.starts_with("copyright") |
| { |
| let license_file_label = format!( |
| "//{}", |
| entry |
| .path() |
| .canonicalize() |
| .unwrap() |
| .strip_prefix(project_root) |
| .unwrap() |
| .to_string_lossy() |
| ); |
| license_files.push(license_file_label); |
| license_files_found = true; |
| } |
| } |
| |
| if license_files_found { |
| if uses_fuchsia_license { |
| anyhow::bail!("ERROR: Crate {}.{} has license files but is set with uses_fuchsia_license = true", target.name(), target.version()) |
| } |
| |
| // Define a license target |
| let license_target_name = format!("{}.license", target_name); |
| // Directory iteration order is random, so sort alphabetically. |
| license_files.sort(); |
| let mut license_files_param = GnField::new("license_files"); |
| for entry in license_files { |
| license_files_param.add_cfg(entry); |
| } |
| |
| writeln!( |
| output, |
| include_str!("../templates_pw/gn_license.template"), |
| target_name = license_target_name, |
| public_package_name = gn_crate_name, |
| license_files = license_files_param.render_gn(), |
| )?; |
| |
| applicable_licenses.add_cfg(format!(":{}", license_target_name)); |
| } else if uses_fuchsia_license || |
| // Empty crates are stubs crates authored by Fuchsia. |
| target.package_root().parent().unwrap().ends_with("third_party/rust_crates/empty") |
| { |
| applicable_licenses.add_cfg("//build/licenses:fuchsia_license"); |
| } else if require_licenses { |
| anyhow::bail!( |
| "ERROR: Crate at {} must have LICENSE* or COPYRIGHT files. |
| |
| Make sure such files are placed at the crate's root folder. |
| |
| Alternatively, if the crate's license is the same as Fuchsia's, |
| modify //third_party/rust_crates/Cargo.toml by adding: |
| |
| ``` |
| [gn.package.{}.\"{}\"] |
| uses_fuchsia_license = true |
| ```", |
| target.package_root(), |
| target.name(), |
| target.version() |
| ); |
| } |
| |
| gn_applicable_licenses = Some(applicable_licenses); |
| } |
| |
| writeln!( |
| output, |
| include_str!("../templates_pw/gn_rule.template"), |
| gn_rule = gn_rule, |
| target_name = target_name, |
| crate_name = gn_crate_name, |
| output_name = output_name, |
| root_path = root_relative_path, |
| aliased_deps = aliased_deps_str, |
| dependencies = dependencies, |
| cfgs = configs.render_gn(), |
| rustenv = rustenv.render_gn(), |
| rustflags = rustflags.render_gn(), |
| edition = edition, |
| visibility = visibility, |
| optional_testonly = optional_testonly, |
| applicable_licenses = |
| if let Some(applicable_licenses) = gn_applicable_licenses { |
| applicable_licenses.render_gn() |
| } else { |
| "".to_string() |
| } |
| ) |
| .map_err(Into::into) |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use camino::Utf8Path; |
| use cargo_metadata::Edition; |
| use semver::Version; |
| use std::collections::HashMap; |
| |
| // WARNING: the expected output tests below have non-printable artifacts |
| // due to the way the templates are generated. Do not remove extra spaces |
| // in the quoted strings. |
| |
| #[test] |
| fn canonicalized_paths() { |
| let pkg_id = cargo_metadata::PackageId { repr: String::from("42") }; |
| let version = Version::new(0, 1, 0); |
| |
| let mut project_root = std::env::temp_dir(); |
| project_root.push(Path::new("canonicalized_paths")); |
| std::fs::write(&project_root, "").expect("write to temp file"); |
| |
| let target = GnTarget::new( |
| &pkg_id, |
| "test_target", |
| "test_package", |
| Edition::E2018, |
| Utf8Path::from_path(project_root.as_path()).unwrap(), |
| &version, |
| GnRustType::Library, |
| &[], |
| false, |
| HashMap::new(), |
| ); |
| |
| let not_prefix = Path::new("/foo"); |
| let prefix = std::env::temp_dir(); |
| |
| let mut output = vec![]; |
| assert!(write_rule( |
| &mut output, |
| &target, |
| not_prefix, |
| None, |
| None, |
| None, |
| false, |
| false, |
| None, |
| false |
| ) |
| .is_err()); |
| assert!(write_rule( |
| &mut output, |
| &target, |
| prefix.as_path(), |
| None, |
| None, |
| None, |
| false, |
| false, |
| None, |
| false, |
| ) |
| .is_ok()); |
| } |
| |
| #[test] |
| fn simple_target() { |
| let pkg_id = cargo_metadata::PackageId { repr: String::from("42") }; |
| let version = Version::new(0, 1, 0); |
| |
| let mut project_root = std::env::temp_dir(); |
| project_root.push(Path::new("simple_target")); |
| std::fs::write(&project_root, "").expect("write to temp file"); |
| |
| let target = GnTarget::new( |
| &pkg_id, |
| "test_target", |
| "test_package", |
| Edition::E2018, |
| Utf8Path::from_path(project_root.as_path()).unwrap(), |
| &version, |
| GnRustType::Library, |
| &[], |
| false, |
| HashMap::new(), |
| ); |
| |
| let mut output = vec![]; |
| write_rule( |
| &mut output, |
| &target, |
| std::env::temp_dir().as_path(), |
| None, |
| None, |
| None, |
| false, |
| false, |
| None, |
| false, |
| ) |
| .unwrap(); |
| let output = String::from_utf8(output).unwrap(); |
| assert_eq!( |
| output, |
| r#"pw_rust_library("test_package-v0_1_0") { |
| crate_name = "test_target" |
| crate_root = "//simple_target" |
| output_name = "test_target-c5bf97c44457465a" |
| |
| deps = [] |
| |
| rustenv = [] |
| |
| rustflags = ["--cap-lints=allow","-Cmetadata=c5bf97c44457465a","-Cextra-filename=-c5bf97c44457465a"] |
| |
| edition = "2018" |
| |
| visibility = [":*"] |
| |
| |
| |
| } |
| |
| "# |
| ); |
| } |
| |
| #[test] |
| fn binary_target() { |
| let pkg_id = cargo_metadata::PackageId { repr: String::from("42") }; |
| let version = Version::new(0, 1, 0); |
| |
| let mut project_root = std::env::temp_dir(); |
| project_root.push(Path::new("binary_target")); |
| std::fs::write(&project_root, "").expect("write to temp file"); |
| |
| let target = GnTarget::new( |
| &pkg_id, |
| "test_target", |
| "test_package", |
| Edition::E2018, |
| Utf8Path::from_path(project_root.as_path()).unwrap(), |
| &version, |
| GnRustType::Binary, |
| &[], |
| false, |
| HashMap::new(), |
| ); |
| |
| let outname = Some("rainbow_binary"); |
| let mut output = vec![]; |
| write_rule( |
| &mut output, |
| &target, |
| std::env::temp_dir().as_path(), |
| None, |
| None, |
| outname, |
| false, |
| false, |
| None, |
| false, |
| ) |
| .unwrap(); |
| |
| let output = String::from_utf8(output).unwrap(); |
| assert_eq!( |
| output, |
| r#"pw_executable("test_package-test_target-v0_1_0") { |
| crate_name = "test_target" |
| crate_root = "//binary_target" |
| output_name = "rainbow_binary" |
| |
| deps = [] |
| |
| rustenv = [] |
| |
| rustflags = ["--cap-lints=allow","-Cmetadata=bf8f4a806276c599","-Cextra-filename=-bf8f4a806276c599"] |
| |
| edition = "2018" |
| |
| visibility = [":*"] |
| |
| |
| |
| } |
| |
| "# |
| ); |
| } |
| |
| #[test] |
| fn renamed_target() { |
| let pkg_id = cargo_metadata::PackageId { repr: String::from("42") }; |
| let version = Version::new(0, 1, 0); |
| |
| let mut project_root = std::env::temp_dir(); |
| project_root.push(Path::new("renamed_target")); |
| std::fs::write(&project_root, "").expect("write to temp file"); |
| |
| let target = GnTarget::new( |
| &pkg_id, |
| "test_target", |
| "test_package", |
| Edition::E2018, |
| Utf8Path::from_path(project_root.as_path()).unwrap(), |
| &version, |
| GnRustType::Binary, |
| &[], |
| false, |
| HashMap::new(), |
| ); |
| |
| let outname = Some("rainbow_binary"); |
| let mut output = vec![]; |
| write_rule( |
| &mut output, |
| &target, |
| std::env::temp_dir().as_path(), |
| None, |
| None, |
| outname, |
| false, |
| false, |
| Some("renamed_rule"), |
| false, |
| ) |
| .unwrap(); |
| let output = String::from_utf8(output).unwrap(); |
| assert_eq!( |
| output, |
| r#"pw_renamed_rule("test_package-test_target-v0_1_0") { |
| crate_name = "test_target" |
| crate_root = "//renamed_target" |
| output_name = "rainbow_binary" |
| |
| deps = [] |
| |
| rustenv = [] |
| |
| rustflags = ["--cap-lints=allow","-Cmetadata=bf8f4a806276c599","-Cextra-filename=-bf8f4a806276c599"] |
| |
| edition = "2018" |
| |
| visibility = [":*"] |
| |
| |
| |
| } |
| |
| "# |
| ); |
| } |
| } |