| // Copyright 2019 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. |
| |
| mod constants; |
| mod fake_font_info_loader; |
| mod font_catalog; |
| mod font_db; |
| mod font_pkgs; |
| mod font_sets; |
| mod generator; |
| mod merge; |
| mod product_config; |
| mod serde_ext; |
| |
| pub(crate) use crate::font_catalog::{FontCatalog, TypefaceInAssetIndex}; |
| pub(crate) use crate::font_pkgs::FontPackageListing; |
| pub(crate) use crate::font_sets::{FontSet, FontSets}; |
| pub(crate) use crate::product_config::{FallbackChainEntry, ProductConfig}; |
| |
| use { |
| anyhow::Error, |
| fake_font_info_loader::FakeFontInfoLoaderImpl, |
| font_info::{FontAssetSource, FontInfo, FontInfoLoader, FontInfoLoaderImpl}, |
| manifest::{v2::FontsManifest, FontManifestWrapper}, |
| std::{ |
| env, fs, |
| io::{self, Write}, |
| path::PathBuf, |
| }, |
| structopt::StructOpt, |
| }; |
| |
| #[derive(Debug, StructOpt)] |
| #[structopt(name = "Font Manifest Generator")] |
| struct Args { |
| #[structopt( |
| long = "empty", |
| raw( |
| conflicts_with_all = r#"&["all_fonts", "local_fonts", "font_pkgs", "font_catalog", "product_config", "font_dir", "fake_code_points"]"# |
| ), |
| help = "If true, generates an empty manifest" |
| )] |
| empty: bool, |
| |
| #[structopt( |
| long = "all-fonts", |
| required_unless = "empty", |
| value_name = "FILE", |
| help = "Path to local_fonts.json file containing list of all font file names for the target product, generated by GN." |
| )] |
| all_fonts: Option<PathBuf>, |
| |
| #[structopt( |
| long = "local-fonts", |
| required_unless = "empty", |
| value_name = "FILE", |
| help = "Path to local_fonts.json file containing list of *local* font file names for the target product, generated by GN." |
| )] |
| local_fonts: Option<PathBuf>, |
| |
| #[structopt( |
| long = "font-pkgs", |
| required_unless = "empty", |
| value_name = "FILE", |
| help = "Paths to .font_pkgs.json files, each containing a list of all font files and Fuchsia package names available in a CIPD fonts repo, generated by LUCI. There should be one file for each CIPD fonts repo used for the target product." |
| )] |
| font_pkgs: Vec<PathBuf>, |
| |
| #[structopt( |
| long = "font-catalog", |
| required_unless = "empty", |
| value_name = "FILE", |
| help = "Paths to .font_catalog.json files, each containing an index of all font families, assets, and typefaces available in a CIPD fonts repo. This file is maintained by hand. There should be one file for each CIPD fonts repo used for the target product." |
| )] |
| font_catalog: Vec<PathBuf>, |
| |
| #[structopt( |
| long = "product-config", |
| value_name = "FILE", |
| help = "Path to a .fontcfg.json file, containing font configurations for the target product, including a fallback sequence of typefaces. This file is maintained by hand." |
| )] |
| product_config: Option<PathBuf>, |
| |
| #[structopt( |
| long = "font-dir", |
| value_name = "DIR", |
| required_unless = "empty", |
| help = "Path to the base directory containing all font files checked out from CIPD. Usually, this will end in \"prebuilt/third_party/fonts\"." |
| )] |
| font_dir: Option<PathBuf>, |
| |
| #[structopt( |
| long = "fake-code-points", |
| help = "If true, will write fake code points instead of trying to read actual font files." |
| )] |
| fake_code_points: bool, |
| |
| #[structopt(long = "pretty-print", help = "If true, indents output JSON.")] |
| pretty_print: bool, |
| |
| #[structopt( |
| long = "verbose", |
| short = "v", |
| help = "If true, outputs extra logs while generating the manifest" |
| )] |
| verbose: bool, |
| |
| #[structopt( |
| long = "output", |
| value_name = "FILE", |
| help = "Optional path to output file ending in .font_manifest.json. If omitted, writes to STDOUT." |
| )] |
| output: Option<PathBuf>, |
| |
| #[structopt( |
| long = "target-asset-dir", |
| value_name = "DIR", |
| help = "The directory to store local font files asset into", |
| default_value = "/config/data/assets" |
| )] |
| target_asset_dir: PathBuf, |
| } |
| |
| /// Required because Rust can't create trait objects (`dyn FontInfoLoader`) with generic methods. |
| enum FontInfoLoaderType { |
| Real(FontInfoLoaderImpl), |
| Fake(FakeFontInfoLoaderImpl), |
| } |
| |
| impl FontInfoLoader for FontInfoLoaderType { |
| fn load_font_info<S, E>(&self, source: S, index: u32) -> Result<FontInfo, Error> |
| where |
| S: Sized + TryInto<FontAssetSource, Error = E>, |
| E: Sized + Sync + Send + Into<Error>, |
| { |
| match self { |
| FontInfoLoaderType::Real(loader) => loader.load_font_info(source, index), |
| FontInfoLoaderType::Fake(loader) => loader.load_font_info(source, index), |
| } |
| } |
| } |
| |
| fn main() -> Result<(), Error> { |
| env::set_var("RUST_BACKTRACE", "full"); |
| |
| let args: Args = Args::from_args(); |
| |
| let manifest = if args.empty { |
| FontManifestWrapper::Version2(FontsManifest::empty()) |
| } else { |
| let font_sets = FontSets::load_from_all_and_local_paths( |
| args.all_fonts.unwrap(), |
| args.local_fonts.unwrap(), |
| )?; |
| let font_pkgs = FontPackageListing::load_from_paths(args.font_pkgs)?; |
| let font_catalog = FontCatalog::load_from_paths(args.font_catalog)?; |
| let product_config = args.product_config.map_or_else( |
| || Ok(ProductConfig::default()), |
| |path| ProductConfig::load_from_path(path), |
| )?; |
| |
| let font_info_loader = if args.fake_code_points { |
| FontInfoLoaderType::Fake(FakeFontInfoLoaderImpl::new()) |
| } else { |
| FontInfoLoaderType::Real(FontInfoLoaderImpl::new()?) |
| }; |
| |
| generator::generate_manifest( |
| font_catalog, |
| font_pkgs, |
| font_sets, |
| product_config, |
| font_info_loader, |
| args.font_dir.unwrap(), |
| args.verbose, |
| args.target_asset_dir, |
| )? |
| }; |
| |
| let manifest_str = if args.pretty_print { |
| serde_json::to_string_pretty(&manifest) |
| } else { |
| serde_json::to_string(&manifest) |
| }?; |
| |
| if let Some(output_path) = args.output { |
| fs::write(output_path, manifest_str.as_bytes())?; |
| } else { |
| io::stdout().write_all(manifest_str.as_bytes())?; |
| } |
| |
| Ok(()) |
| } |