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) -> Option<&str>76 pub fn get_string(&self, k: &str) -> Option<&str> { 77 match self.map.get(k)? { 78 BpValue::String(s) => Some(s), 79 _ => None, 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 "host_cross_supported", 112 "crate_name", 113 "cargo_env_compat", 114 "cargo_pkg_version", 115 "crate_root", 116 "srcs", 117 "test_suites", 118 "auto_gen_config", 119 "test_options", 120 "edition", 121 "features", 122 "cfgs", 123 "flags", 124 "rustlibs", 125 "proc_macros", 126 "static_libs", 127 "whole_static_libs", 128 "shared_libs", 129 "aliases", 130 "arch", 131 "target", 132 "ld_flags", 133 "compile_multilib", 134 "include_dirs", 135 "apex_available", 136 "prefer_rlib", 137 "no_stdlibs", 138 "stdlibs", 139 "native_bridge_supported", 140 "product_available", 141 "recovery_available", 142 "vendor_available", 143 "vendor_ramdisk_available", 144 "ramdisk_available", 145 "min_sdk_version", 146 "visibility", 147 ]; 148 let mut props: Vec<(&String, &BpValue)> = self.map.iter().collect(); 149 props.sort_by_key(|(k, _)| { 150 let i = canonical_order.iter().position(|x| k == x).unwrap_or(canonical_order.len()); 151 (i, (*k).clone()) 152 }); 153 for (k, v) in props { 154 w.write_str(k)?; 155 w.write_str(": ")?; 156 v.write(w)?; 157 w.write_str(",\n")?; 158 } 159 if let Some(raw_block) = &self.raw_block { 160 w.write_str(raw_block)?; 161 w.write_str(",\n")?; 162 } 163 w.write_str("}")?; 164 Ok(()) 165 } 166 } 167 168 impl BpValue { 169 /// Serialize to Android.bp format. write(&self, w: &mut impl std::fmt::Write) -> Result<()>170 pub fn write(&self, w: &mut impl std::fmt::Write) -> Result<()> { 171 match self { 172 BpValue::Object(p) => p.write(w)?, 173 BpValue::Bool(b) => write!(w, "{b}")?, 174 BpValue::String(s) => write!(w, "\"{s}\"")?, 175 BpValue::List(vs) => { 176 w.write_str("[")?; 177 for (i, v) in vs.iter().enumerate() { 178 v.write(w)?; 179 if i != vs.len() - 1 { 180 w.write_str(", ")?; 181 } 182 } 183 w.write_str("]")?; 184 } 185 } 186 Ok(()) 187 } 188 } 189 190 impl From<bool> for BpValue { from(x: bool) -> Self191 fn from(x: bool) -> Self { 192 BpValue::Bool(x) 193 } 194 } 195 196 impl From<&str> for BpValue { from(x: &str) -> Self197 fn from(x: &str) -> Self { 198 BpValue::String(x.to_string()) 199 } 200 } 201 202 impl From<String> for BpValue { from(x: String) -> Self203 fn from(x: String) -> Self { 204 BpValue::String(x) 205 } 206 } 207 208 impl From<PathBuf> for BpValue { from(x: PathBuf) -> Self209 fn from(x: PathBuf) -> Self { 210 BpValue::String(x.to_string_lossy().into_owned()) 211 } 212 } 213 214 impl<T: Into<BpValue>> From<Vec<T>> for BpValue { from(x: Vec<T>) -> Self215 fn from(x: Vec<T>) -> Self { 216 BpValue::List(x.into_iter().map(|x| x.into()).collect()) 217 } 218 } 219