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 = "SelectSet::is_empty")]
118 pub(crate) proc_macro_deps: SelectSet<Label>,
119 #[serde(skip_serializing_if = "SelectScalar::is_empty")]
120 pub(crate) rundir: SelectScalar<String>,
121 #[serde(skip_serializing_if = "SelectDict::is_empty")]
122 pub(crate) rustc_env: SelectDict<String, String>,
123 #[serde(skip_serializing_if = "SelectSet::is_empty")]
124 pub(crate) rustc_env_files: SelectSet<String>,
125 #[serde(skip_serializing_if = "SelectList::is_empty")]
126 pub(crate) rustc_flags: SelectList<String>,
127 pub(crate) srcs: Glob,
128 #[serde(skip_serializing_if = "Set::is_empty")]
129 pub(crate) tags: Set<String>,
130 #[serde(skip_serializing_if = "SelectSet::is_empty")]
131 pub(crate) tools: SelectSet<Label>,
132 #[serde(skip_serializing_if = "Set::is_empty")]
133 pub(crate) toolchains: Set<Label>,
134 pub(crate) version: String,
135 pub(crate) visibility: Set<String>,
136 }
137
138 #[derive(Serialize)]
139 pub(crate) struct RustProcMacro {
140 pub(crate) name: String,
141 #[serde(skip_serializing_if = "SelectSet::is_empty")]
142 pub(crate) deps: SelectSet<Label>,
143 #[serde(skip_serializing_if = "SelectSet::is_empty")]
144 pub(crate) proc_macro_deps: SelectSet<Label>,
145 #[serde(skip_serializing_if = "SelectDict::is_empty")]
146 pub(crate) aliases: SelectDict<Label, String>,
147 #[serde(flatten)]
148 pub(crate) common: CommonAttrs,
149 }
150
151 #[derive(Serialize)]
152 pub(crate) struct RustLibrary {
153 pub(crate) name: String,
154 #[serde(skip_serializing_if = "SelectSet::is_empty")]
155 pub(crate) deps: SelectSet<Label>,
156 #[serde(skip_serializing_if = "SelectSet::is_empty")]
157 pub(crate) proc_macro_deps: SelectSet<Label>,
158 #[serde(skip_serializing_if = "SelectDict::is_empty")]
159 pub(crate) aliases: SelectDict<Label, String>,
160 #[serde(flatten)]
161 pub(crate) common: CommonAttrs,
162 #[serde(skip_serializing_if = "std::ops::Not::not")]
163 pub(crate) disable_pipelining: bool,
164 }
165
166 #[derive(Serialize)]
167 pub(crate) struct RustBinary {
168 pub(crate) name: String,
169 #[serde(skip_serializing_if = "SelectSet::is_empty")]
170 pub(crate) deps: SelectSet<Label>,
171 #[serde(skip_serializing_if = "SelectSet::is_empty")]
172 pub(crate) proc_macro_deps: SelectSet<Label>,
173 #[serde(skip_serializing_if = "SelectDict::is_empty")]
174 pub(crate) aliases: SelectDict<Label, String>,
175 #[serde(flatten)]
176 pub(crate) common: CommonAttrs,
177 }
178
179 #[derive(Serialize)]
180 pub(crate) struct CommonAttrs {
181 #[serde(skip_serializing_if = "Data::is_empty")]
182 pub(crate) compile_data: Data,
183 #[serde(skip_serializing_if = "SelectSet::is_empty")]
184 pub(crate) crate_features: SelectSet<String>,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub(crate) crate_root: Option<String>,
187 #[serde(skip_serializing_if = "Data::is_empty")]
188 pub(crate) data: Data,
189 pub(crate) edition: String,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub(crate) linker_script: Option<String>,
192 #[serde(skip_serializing_if = "SelectDict::is_empty")]
193 pub(crate) rustc_env: SelectDict<String, String>,
194 #[serde(skip_serializing_if = "SelectSet::is_empty")]
195 pub(crate) rustc_env_files: SelectSet<String>,
196 #[serde(skip_serializing_if = "SelectList::is_empty")]
197 pub(crate) rustc_flags: SelectList<String>,
198 pub(crate) srcs: Glob,
199 #[serde(skip_serializing_if = "Set::is_empty")]
200 pub(crate) tags: Set<String>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub(crate) target_compatible_with: Option<TargetCompatibleWith>,
203 pub(crate) version: String,
204 }
205
206 pub(crate) struct Data {
207 pub(crate) glob: Glob,
208 pub(crate) select: SelectSet<Label>,
209 }
210
211 impl Package {
default_visibility_public(default_package_metadata: Set<Label>) -> Self212 pub(crate) fn default_visibility_public(default_package_metadata: Set<Label>) -> Self {
213 let mut default_visibility = Set::new();
214 default_visibility.insert("//visibility:public".to_owned());
215 Package {
216 default_package_metadata,
217 default_visibility,
218 }
219 }
220 }
221
222 impl Serialize for Alias {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,223 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
224 where
225 S: Serializer,
226 {
227 // Output looks like:
228 //
229 // rule(
230 // name = "name",
231 // actual = "actual",
232 // tags = [
233 // "tag1",
234 // "tag2",
235 // ],
236 // )
237
238 #[derive(Serialize)]
239 struct AliasInner<'a> {
240 pub(crate) name: &'a String,
241 pub(crate) actual: &'a Label,
242 pub(crate) tags: &'a Set<String>,
243 }
244
245 FunctionCall::new(
246 &self.rule,
247 AliasInner {
248 name: &self.name,
249 actual: &self.actual,
250 tags: &self.tags,
251 },
252 )
253 .serialize(serializer)
254 }
255 }
256
serialize(starlark: &[Starlark]) -> Result<String, StarlarkError>257 pub(crate) fn serialize(starlark: &[Starlark]) -> Result<String, StarlarkError> {
258 let mut content = String::new();
259 for call in starlark {
260 if !content.is_empty() {
261 content.push('\n');
262 }
263 if let Starlark::Verbatim(comment) = call {
264 content.push_str(comment);
265 } else {
266 content.push_str(&serde_starlark::to_string(call)?);
267 }
268 }
269 Ok(content)
270 }
271