1 // Copyright (C) 2022 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use anyhow::Result; 16 use std::collections::BTreeMap; 17 use std::path::PathBuf; 18 19 /// Build module. 20 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 21 pub struct BpModule { 22 pub module_type: String, 23 pub props: BpProperties, 24 } 25 26 /// Properties of a build module, or of a nested object value. 27 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 28 pub struct BpProperties { 29 pub map: BTreeMap<String, BpValue>, 30 /// A raw block of text to append after the last key-value pair, but before the closing brace. 31 /// For example, if you have the properties 32 /// 33 /// { 34 /// name: "foo", 35 /// srcs: ["main.rs"], 36 /// } 37 /// 38 /// and add `raw_block = "some random text"`, you'll get 39 /// 40 /// { 41 /// name: "foo", 42 /// srcs: ["main.rs"], 43 /// some random text 44 /// } 45 pub raw_block: Option<String>, 46 } 47 48 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 49 pub enum BpValue { 50 Object(BpProperties), 51 Bool(bool), 52 String(String), 53 List(Vec<BpValue>), 54 } 55 56 impl BpModule { new(module_type: String) -> BpModule57 pub fn new(module_type: String) -> BpModule { 58 BpModule { module_type, props: BpProperties::new() } 59 } 60 61 /// Serialize to Android.bp format. write(&self, w: &mut impl std::fmt::Write) -> Result<()>62 pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { 63 w.write_str(&self.module_type)?; 64 w.write_str(" ")?; 65 self.props.write(w)?; 66 w.write_str("\n")?; 67 Ok(()) 68 } 69 } 70 71 impl BpProperties { new() -> Self72 pub fn new() -> Self { 73 BpProperties { map: BTreeMap::new(), raw_block: None } 74 } 75 get_string(&self, k: &str) -> &str76 pub fn get_string(&self, k: &str) -> &str { 77 match self.map.get(k).unwrap() { 78 BpValue::String(s) => s, 79 _ => unreachable!(), 80 } 81 } 82 set<T: Into<BpValue>>(&mut self, k: &str, v: T)83 pub fn set<T: Into<BpValue>>(&mut self, k: &str, v: T) { 84 self.map.insert(k.to_string(), v.into()); 85 } 86 set_if_nonempty<T: Into<BpValue>>(&mut self, k: &str, v: Vec<T>)87 pub fn set_if_nonempty<T: Into<BpValue>>(&mut self, k: &str, v: Vec<T>) { 88 if !v.is_empty() { 89 self.set(k, v); 90 } 91 } 92 object(&mut self, k: &str) -> &mut BpProperties93 pub fn object(&mut self, k: &str) -> &mut BpProperties { 94 let v = 95 self.map.entry(k.to_string()).or_insert_with(|| BpValue::Object(BpProperties::new())); 96 match v { 97 BpValue::Object(v) => v, 98 _ => panic!("key {k:?} already has non-object value"), 99 } 100 } 101 102 /// Serialize to Android.bp format. write(&self, w: &mut impl std::fmt::Write) -> Result<()>103 pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { 104 w.write_str("{\n")?; 105 // Sort stuff to match what cargo2android.py's output order. 106 let canonical_order = &[ 107 "name", 108 "defaults", 109 "stem", 110 "host_supported", 111 "crate_name", 112 "cargo_env_compat", 113 "cargo_pkg_version", 114 "crate_root", 115 "srcs", 116 "test_suites", 117 "auto_gen_config", 118 "test_options", 119 "edition", 120 "features", 121 "cfgs", 122 "flags", 123 "rustlibs", 124 "proc_macros", 125 "static_libs", 126 "whole_static_libs", 127 "shared_libs", 128 "aliases", 129 "arch", 130 "target", 131 "ld_flags", 132 "compile_multilib", 133 "include_dirs", 134 "apex_available", 135 "prefer_rlib", 136 "no_stdlibs", 137 "stdlibs", 138 "native_bridge_supported", 139 "product_available", 140 "recovery_available", 141 "vendor_available", 142 "vendor_ramdisk_available", 143 "ramdisk_available", 144 "min_sdk_version", 145 "visibility", 146 ]; 147 let mut props: Vec<(&String, &BpValue)> = self.map.iter().collect(); 148 props.sort_by_key(|(k, _)| { 149 let i = canonical_order.iter().position(|x| k == x).unwrap_or(canonical_order.len()); 150 (i, (*k).clone()) 151 }); 152 for (k, v) in props { 153 w.write_str(k)?; 154 w.write_str(": ")?; 155 v.write(w)?; 156 w.write_str(",\n")?; 157 } 158 if let Some(raw_block) = &self.raw_block { 159 w.write_str(raw_block)?; 160 w.write_str(",\n")?; 161 } 162 w.write_str("}")?; 163 Ok(()) 164 } 165 } 166 167 impl BpValue { 168 /// Serialize to Android.bp format. write(&self, w: &mut impl std::fmt::Write) -> Result<()>169 pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { 170 match self { 171 BpValue::Object(p) => p.write(w)?, 172 BpValue::Bool(b) => write!(w, "{b}")?, 173 BpValue::String(s) => write!(w, "\"{s}\"")?, 174 BpValue::List(vs) => { 175 w.write_str("[")?; 176 for (i, v) in vs.iter().enumerate() { 177 v.write(w)?; 178 if i != vs.len() - 1 { 179 w.write_str(", ")?; 180 } 181 } 182 w.write_str("]")?; 183 } 184 } 185 Ok(()) 186 } 187 } 188 189 impl From<bool> for BpValue { from(x: bool) -> Self190 fn from(x: bool) -> Self { 191 BpValue::Bool(x) 192 } 193 } 194 195 impl From<&str> for BpValue { from(x: &str) -> Self196 fn from(x: &str) -> Self { 197 BpValue::String(x.to_string()) 198 } 199 } 200 201 impl From<String> for BpValue { from(x: String) -> Self202 fn from(x: String) -> Self { 203 BpValue::String(x) 204 } 205 } 206 207 impl From<PathBuf> for BpValue { from(x: PathBuf) -> Self208 fn from(x: PathBuf) -> Self { 209 BpValue::String(x.to_string_lossy().into_owned()) 210 } 211 } 212 213 impl<T: Into<BpValue>> From<Vec<T>> for BpValue { from(x: Vec<T>) -> Self214 fn from(x: Vec<T>) -> Self { 215 BpValue::List(x.into_iter().map(|x| x.into()).collect()) 216 } 217 } 218