1 //! A module for representations of starlark constructs
2
3 mod glob;
4 mod label;
5 mod select;
6 mod select_dict;
7 mod select_list;
8 mod select_scalar;
9 mod select_set;
10 mod serialize;
11 mod target_compatible_with;
12
13 use std::collections::BTreeSet as Set;
14
15 use serde::{Serialize, Serializer};
16 use serde_starlark::{Error as StarlarkError, FunctionCall};
17
18 pub(crate) use glob::*;
19 pub(crate) use label::*;
20 pub(crate) use select::*;
21 pub(crate) use select_dict::*;
22 pub(crate) use select_list::*;
23 pub(crate) use select_scalar::*;
24 pub(crate) use select_set::*;
25 pub(crate) use target_compatible_with::*;
26
27 #[derive(Serialize)]
28 #[serde(untagged)]
29 pub(crate) enum Starlark {
30 Load(Load),
31 Package(Package),
32 PackageInfo(PackageInfo),
33 License(License),
34 ExportsFiles(ExportsFiles),
35 Filegroup(Filegroup),
36 Alias(Alias),
37 CargoBuildScript(CargoBuildScript),
38 #[serde(serialize_with = "serialize::rust_proc_macro")]
39 RustProcMacro(RustProcMacro),
40 #[serde(serialize_with = "serialize::rust_library")]
41 RustLibrary(RustLibrary),
42 #[serde(serialize_with = "serialize::rust_binary")]
43 RustBinary(RustBinary),
44
45 #[serde(skip_serializing)]
46 Verbatim(String),
47 }
48
49 pub(crate) struct Load {
50 pub(crate) bzl: String,
51 pub(crate) items: Set<String>,
52 }
53
54 pub(crate) struct Package {
55 pub(crate) default_package_metadata: Set<Label>,
56 pub(crate) default_visibility: Set<String>,
57 }
58
59 pub(crate) struct PackageInfo {
60 pub(crate) name: String,
61 pub(crate) package_name: String,
62 pub(crate) package_url: String,
63 pub(crate) package_version: String,
64 }
65
66 pub(crate) struct License {
67 pub(crate) name: String,
68 pub(crate) license_kinds: Set<String>,
69 pub(crate) license_text: String,
70 }
71
72 pub(crate) struct ExportsFiles {
73 pub(crate) paths: Set<String>,
74 pub(crate) globs: Glob,
75 }
76
77 #[derive(Serialize)]
78 #[serde(rename = "filegroup")]
79 pub(crate) struct Filegroup {
80 pub(crate) name: String,
81 pub(crate) srcs: Glob,
82 }
83
84 pub(crate) struct Alias {
85 pub(crate) rule: String,
86 pub(crate) name: String,
87 pub(crate) actual: Label,
88 pub(crate) tags: Set<String>,
89 }
90
91 #[derive(Serialize)]
92 #[serde(rename = "cargo_build_script")]
93 pub(crate) struct CargoBuildScript {
94 pub(crate) name: String,
95 #[serde(skip_serializing_if = "SelectDict::is_empty")]
96 pub(crate) aliases: SelectDict<Label, String>,
97 #[serde(skip_serializing_if = "SelectDict::is_empty")]
98 pub(crate) build_script_env: SelectDict<String, String>,
99 #[serde(skip_serializing_if = "Data::is_empty")]
100 pub(crate) compile_data: Data,
101 #[serde(skip_serializing_if = "SelectSet::is_empty")]
102 pub(crate) crate_features: SelectSet<String>,
103 pub(crate) crate_name: String,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub(crate) crate_root: Option<String>,
106 #[serde(skip_serializing_if = "Data::is_empty")]
107 pub(crate) data: Data,
108 #[serde(skip_serializing_if = "SelectSet::is_empty")]
109 pub(crate) deps: SelectSet<Label>,
110 #[serde(skip_serializing_if = "SelectSet::is_empty")]
111 pub(crate) link_deps: SelectSet<Label>,
112 pub(crate) edition: String,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub(crate) linker_script: Option<String>,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub(crate) links: Option<String>,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub(crate) pkg_name: Option<String>,
119 #[serde(skip_serializing_if = "SelectSet::is_empty")]
120 pub(crate) proc_macro_deps: SelectSet<Label>,
121 #[serde(skip_serializing_if = "SelectScalar::is_empty")]
122 pub(crate) rundir: SelectScalar<String>,
123 #[serde(skip_serializing_if = "SelectDict::is_empty")]
124 pub(crate) rustc_env: SelectDict<String, String>,
125 #[serde(skip_serializing_if = "SelectSet::is_empty")]
126 pub(crate) rustc_env_files: SelectSet<String>,
127 #[serde(skip_serializing_if = "SelectList::is_empty")]
128 pub(crate) rustc_flags: SelectList<String>,
129 pub(crate) srcs: Glob,
130 #[serde(skip_serializing_if = "Set::is_empty")]
131 pub(crate) tags: Set<String>,
132 #[serde(skip_serializing_if = "SelectSet::is_empty")]
133 pub(crate) tools: SelectSet<Label>,
134 #[serde(skip_serializing_if = "Set::is_empty")]
135 pub(crate) toolchains: Set<Label>,
136 pub(crate) version: String,
137 pub(crate) visibility: Set<String>,
138 }
139
140 #[derive(Serialize)]
141 pub(crate) struct RustProcMacro {
142 pub(crate) name: String,
143 #[serde(skip_serializing_if = "SelectSet::is_empty")]
144 pub(crate) deps: SelectSet<Label>,
145 #[serde(skip_serializing_if = "SelectSet::is_empty")]
146 pub(crate) proc_macro_deps: SelectSet<Label>,
147 #[serde(skip_serializing_if = "SelectDict::is_empty")]
148 pub(crate) aliases: SelectDict<Label, String>,
149 #[serde(flatten)]
150 pub(crate) common: CommonAttrs,
151 }
152
153 #[derive(Serialize)]
154 pub(crate) struct RustLibrary {
155 pub(crate) name: String,
156 #[serde(skip_serializing_if = "SelectSet::is_empty")]
157 pub(crate) deps: SelectSet<Label>,
158 #[serde(skip_serializing_if = "SelectSet::is_empty")]
159 pub(crate) proc_macro_deps: SelectSet<Label>,
160 #[serde(skip_serializing_if = "SelectDict::is_empty")]
161 pub(crate) aliases: SelectDict<Label, String>,
162 #[serde(flatten)]
163 pub(crate) common: CommonAttrs,
164 #[serde(skip_serializing_if = "std::ops::Not::not")]
165 pub(crate) disable_pipelining: bool,
166 }
167
168 #[derive(Serialize)]
169 pub(crate) struct RustBinary {
170 pub(crate) name: String,
171 #[serde(skip_serializing_if = "SelectSet::is_empty")]
172 pub(crate) deps: SelectSet<Label>,
173 #[serde(skip_serializing_if = "SelectSet::is_empty")]
174 pub(crate) proc_macro_deps: SelectSet<Label>,
175 #[serde(skip_serializing_if = "SelectDict::is_empty")]
176 pub(crate) aliases: SelectDict<Label, String>,
177 #[serde(flatten)]
178 pub(crate) common: CommonAttrs,
179 }
180
181 #[derive(Serialize)]
182 pub(crate) struct CommonAttrs {
183 #[serde(skip_serializing_if = "Data::is_empty")]
184 pub(crate) compile_data: Data,
185 #[serde(skip_serializing_if = "SelectSet::is_empty")]
186 pub(crate) crate_features: SelectSet<String>,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub(crate) crate_root: Option<String>,
189 #[serde(skip_serializing_if = "Data::is_empty")]
190 pub(crate) data: Data,
191 pub(crate) edition: String,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub(crate) linker_script: Option<String>,
194 #[serde(skip_serializing_if = "SelectDict::is_empty")]
195 pub(crate) rustc_env: SelectDict<String, String>,
196 #[serde(skip_serializing_if = "SelectSet::is_empty")]
197 pub(crate) rustc_env_files: SelectSet<String>,
198 #[serde(skip_serializing_if = "SelectList::is_empty")]
199 pub(crate) rustc_flags: SelectList<String>,
200 pub(crate) srcs: Glob,
201 #[serde(skip_serializing_if = "Set::is_empty")]
202 pub(crate) tags: Set<String>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub(crate) target_compatible_with: Option<TargetCompatibleWith>,
205 pub(crate) version: String,
206 }
207
208 pub(crate) struct Data {
209 pub(crate) glob: Glob,
210 pub(crate) select: SelectSet<Label>,
211 }
212
213 impl Package {
default_visibility_public(default_package_metadata: Set<Label>) -> Self214 pub(crate) fn default_visibility_public(default_package_metadata: Set<Label>) -> Self {
215 let mut default_visibility = Set::new();
216 default_visibility.insert("//visibility:public".to_owned());
217 Package {
218 default_package_metadata,
219 default_visibility,
220 }
221 }
222 }
223
224 impl Serialize for Alias {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,225 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
226 where
227 S: Serializer,
228 {
229 // Output looks like:
230 //
231 // rule(
232 // name = "name",
233 // actual = "actual",
234 // tags = [
235 // "tag1",
236 // "tag2",
237 // ],
238 // )
239
240 #[derive(Serialize)]
241 struct AliasInner<'a> {
242 pub(crate) name: &'a String,
243 pub(crate) actual: &'a Label,
244 pub(crate) tags: &'a Set<String>,
245 }
246
247 FunctionCall::new(
248 &self.rule,
249 AliasInner {
250 name: &self.name,
251 actual: &self.actual,
252 tags: &self.tags,
253 },
254 )
255 .serialize(serializer)
256 }
257 }
258
serialize(starlark: &[Starlark]) -> Result<String, StarlarkError>259 pub(crate) fn serialize(starlark: &[Starlark]) -> Result<String, StarlarkError> {
260 let mut content = String::new();
261 for call in starlark {
262 if !content.is_empty() {
263 content.push('\n');
264 }
265 if let Starlark::Verbatim(comment) = call {
266 content.push_str(comment);
267 } else {
268 content.push_str(&serde_starlark::to_string(call)?);
269 }
270 }
271 Ok(content)
272 }
273