// Copyright (C) 2022 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use anyhow::Result; use std::collections::BTreeMap; use std::path::PathBuf; /// Build module. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct BpModule { pub module_type: String, pub props: BpProperties, } /// Properties of a build module, or of a nested object value. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct BpProperties { pub map: BTreeMap, /// A raw block of text to append after the last key-value pair, but before the closing brace. /// For example, if you have the properties /// /// { /// name: "foo", /// srcs: ["main.rs"], /// } /// /// and add `raw_block = "some random text"`, you'll get /// /// { /// name: "foo", /// srcs: ["main.rs"], /// some random text /// } pub raw_block: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum BpValue { Object(BpProperties), Bool(bool), String(String), List(Vec), } impl BpModule { pub fn new(module_type: String) -> BpModule { BpModule { module_type, props: BpProperties::new() } } /// Serialize to Android.bp format. pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { w.write_str(&self.module_type)?; w.write_str(" ")?; self.props.write(w)?; w.write_str("\n")?; Ok(()) } } impl BpProperties { pub fn new() -> Self { BpProperties { map: BTreeMap::new(), raw_block: None } } pub fn get_string(&self, k: &str) -> &str { match self.map.get(k).unwrap() { BpValue::String(s) => s, _ => unreachable!(), } } pub fn set>(&mut self, k: &str, v: T) { self.map.insert(k.to_string(), v.into()); } pub fn set_if_nonempty>(&mut self, k: &str, v: Vec) { if !v.is_empty() { self.set(k, v); } } pub fn object(&mut self, k: &str) -> &mut BpProperties { let v = self.map.entry(k.to_string()).or_insert_with(|| BpValue::Object(BpProperties::new())); match v { BpValue::Object(v) => v, _ => panic!("key {k:?} already has non-object value"), } } /// Serialize to Android.bp format. pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { w.write_str("{\n")?; // Sort stuff to match what cargo2android.py's output order. let canonical_order = &[ "name", "defaults", "stem", "host_supported", "crate_name", "cargo_env_compat", "cargo_pkg_version", "crate_root", "srcs", "test_suites", "auto_gen_config", "test_options", "edition", "features", "cfgs", "flags", "rustlibs", "proc_macros", "static_libs", "whole_static_libs", "shared_libs", "aliases", "arch", "target", "ld_flags", "compile_multilib", "include_dirs", "apex_available", "prefer_rlib", "no_stdlibs", "stdlibs", "native_bridge_supported", "product_available", "recovery_available", "vendor_available", "vendor_ramdisk_available", "ramdisk_available", "min_sdk_version", "visibility", ]; let mut props: Vec<(&String, &BpValue)> = self.map.iter().collect(); props.sort_by_key(|(k, _)| { let i = canonical_order.iter().position(|x| k == x).unwrap_or(canonical_order.len()); (i, (*k).clone()) }); for (k, v) in props { w.write_str(k)?; w.write_str(": ")?; v.write(w)?; w.write_str(",\n")?; } if let Some(raw_block) = &self.raw_block { w.write_str(raw_block)?; w.write_str(",\n")?; } w.write_str("}")?; Ok(()) } } impl BpValue { /// Serialize to Android.bp format. pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { match self { BpValue::Object(p) => p.write(w)?, BpValue::Bool(b) => write!(w, "{b}")?, BpValue::String(s) => write!(w, "\"{s}\"")?, BpValue::List(vs) => { w.write_str("[")?; for (i, v) in vs.iter().enumerate() { v.write(w)?; if i != vs.len() - 1 { w.write_str(", ")?; } } w.write_str("]")?; } } Ok(()) } } impl From for BpValue { fn from(x: bool) -> Self { BpValue::Bool(x) } } impl From<&str> for BpValue { fn from(x: &str) -> Self { BpValue::String(x.to_string()) } } impl From for BpValue { fn from(x: String) -> Self { BpValue::String(x) } } impl From for BpValue { fn from(x: PathBuf) -> Self { BpValue::String(x.to_string_lossy().into_owned()) } } impl> From> for BpValue { fn from(x: Vec) -> Self { BpValue::List(x.into_iter().map(|x| x.into()).collect()) } }