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