xref: /aosp_15_r20/development/tools/cargo_embargo/src/bp.rs (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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